1/*
2 * HighPoint RR3xxx/4xxx RAID Driver for FreeBSD
3 * Copyright (C) 2007-2012 HighPoint Technologies, Inc. All Rights Reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: stable/11/sys/dev/hptiop/hptiop.c 315812 2017-03-23 06:40:20Z mav $");
29
30#include <sys/param.h>
31#include <sys/types.h>
32#include <sys/cons.h>
33#include <sys/time.h>
34#include <sys/systm.h>
35
36#include <sys/stat.h>
37#include <sys/malloc.h>
38#include <sys/conf.h>
39#include <sys/libkern.h>
40#include <sys/kernel.h>
41
42#include <sys/kthread.h>
43#include <sys/mutex.h>
44#include <sys/module.h>
45
46#include <sys/eventhandler.h>
47#include <sys/bus.h>
48#include <sys/taskqueue.h>
49#include <sys/ioccom.h>
50
51#include <machine/resource.h>
52#include <machine/bus.h>
53#include <machine/stdarg.h>
54#include <sys/rman.h>
55
56#include <vm/vm.h>
57#include <vm/pmap.h>
58
59#include <dev/pci/pcireg.h>
60#include <dev/pci/pcivar.h>
61
62
63#include <cam/cam.h>
64#include <cam/cam_ccb.h>
65#include <cam/cam_sim.h>
66#include <cam/cam_xpt_sim.h>
67#include <cam/cam_debug.h>
68#include <cam/cam_periph.h>
69#include <cam/scsi/scsi_all.h>
70#include <cam/scsi/scsi_message.h>
71
72
73#include <dev/hptiop/hptiop.h>
74
75static const char driver_name[] = "hptiop";
76static const char driver_version[] = "v1.9";
77
78static devclass_t hptiop_devclass;
79
80static int hptiop_send_sync_msg(struct hpt_iop_hba *hba,
81				u_int32_t msg, u_int32_t millisec);
82static void hptiop_request_callback_itl(struct hpt_iop_hba *hba,
83							u_int32_t req);
84static void hptiop_request_callback_mv(struct hpt_iop_hba *hba, u_int64_t req);
85static void hptiop_request_callback_mvfrey(struct hpt_iop_hba *hba,
86							u_int32_t req);
87static void hptiop_os_message_callback(struct hpt_iop_hba *hba, u_int32_t msg);
88static int  hptiop_do_ioctl_itl(struct hpt_iop_hba *hba,
89				struct hpt_iop_ioctl_param *pParams);
90static int  hptiop_do_ioctl_mv(struct hpt_iop_hba *hba,
91				struct hpt_iop_ioctl_param *pParams);
92static int  hptiop_do_ioctl_mvfrey(struct hpt_iop_hba *hba,
93				struct hpt_iop_ioctl_param *pParams);
94static int  hptiop_rescan_bus(struct hpt_iop_hba *hba);
95static int hptiop_alloc_pci_res_itl(struct hpt_iop_hba *hba);
96static int hptiop_alloc_pci_res_mv(struct hpt_iop_hba *hba);
97static int hptiop_alloc_pci_res_mvfrey(struct hpt_iop_hba *hba);
98static int hptiop_get_config_itl(struct hpt_iop_hba *hba,
99				struct hpt_iop_request_get_config *config);
100static int hptiop_get_config_mv(struct hpt_iop_hba *hba,
101				struct hpt_iop_request_get_config *config);
102static int hptiop_get_config_mvfrey(struct hpt_iop_hba *hba,
103				struct hpt_iop_request_get_config *config);
104static int hptiop_set_config_itl(struct hpt_iop_hba *hba,
105				struct hpt_iop_request_set_config *config);
106static int hptiop_set_config_mv(struct hpt_iop_hba *hba,
107				struct hpt_iop_request_set_config *config);
108static int hptiop_set_config_mvfrey(struct hpt_iop_hba *hba,
109				struct hpt_iop_request_set_config *config);
110static int hptiop_internal_memalloc_mv(struct hpt_iop_hba *hba);
111static int hptiop_internal_memalloc_mvfrey(struct hpt_iop_hba *hba);
112static int hptiop_internal_memfree_itl(struct hpt_iop_hba *hba);
113static int hptiop_internal_memfree_mv(struct hpt_iop_hba *hba);
114static int hptiop_internal_memfree_mvfrey(struct hpt_iop_hba *hba);
115static int  hptiop_post_ioctl_command_itl(struct hpt_iop_hba *hba,
116			u_int32_t req32, struct hpt_iop_ioctl_param *pParams);
117static int  hptiop_post_ioctl_command_mv(struct hpt_iop_hba *hba,
118				struct hpt_iop_request_ioctl_command *req,
119				struct hpt_iop_ioctl_param *pParams);
120static int  hptiop_post_ioctl_command_mvfrey(struct hpt_iop_hba *hba,
121				struct hpt_iop_request_ioctl_command *req,
122				struct hpt_iop_ioctl_param *pParams);
123static void hptiop_post_req_itl(struct hpt_iop_hba *hba,
124				struct hpt_iop_srb *srb,
125				bus_dma_segment_t *segs, int nsegs);
126static void hptiop_post_req_mv(struct hpt_iop_hba *hba,
127				struct hpt_iop_srb *srb,
128				bus_dma_segment_t *segs, int nsegs);
129static void hptiop_post_req_mvfrey(struct hpt_iop_hba *hba,
130				struct hpt_iop_srb *srb,
131				bus_dma_segment_t *segs, int nsegs);
132static void hptiop_post_msg_itl(struct hpt_iop_hba *hba, u_int32_t msg);
133static void hptiop_post_msg_mv(struct hpt_iop_hba *hba, u_int32_t msg);
134static void hptiop_post_msg_mvfrey(struct hpt_iop_hba *hba, u_int32_t msg);
135static void hptiop_enable_intr_itl(struct hpt_iop_hba *hba);
136static void hptiop_enable_intr_mv(struct hpt_iop_hba *hba);
137static void hptiop_enable_intr_mvfrey(struct hpt_iop_hba *hba);
138static void hptiop_disable_intr_itl(struct hpt_iop_hba *hba);
139static void hptiop_disable_intr_mv(struct hpt_iop_hba *hba);
140static void hptiop_disable_intr_mvfrey(struct hpt_iop_hba *hba);
141static void hptiop_free_srb(struct hpt_iop_hba *hba, struct hpt_iop_srb *srb);
142static int  hptiop_os_query_remove_device(struct hpt_iop_hba *hba, int tid);
143static int  hptiop_probe(device_t dev);
144static int  hptiop_attach(device_t dev);
145static int  hptiop_detach(device_t dev);
146static int  hptiop_shutdown(device_t dev);
147static void hptiop_action(struct cam_sim *sim, union ccb *ccb);
148static void hptiop_poll(struct cam_sim *sim);
149static void hptiop_async(void *callback_arg, u_int32_t code,
150					struct cam_path *path, void *arg);
151static void hptiop_pci_intr(void *arg);
152static void hptiop_release_resource(struct hpt_iop_hba *hba);
153static void hptiop_reset_adapter(void *argv);
154static d_open_t hptiop_open;
155static d_close_t hptiop_close;
156static d_ioctl_t hptiop_ioctl;
157
158static struct cdevsw hptiop_cdevsw = {
159	.d_open = hptiop_open,
160	.d_close = hptiop_close,
161	.d_ioctl = hptiop_ioctl,
162	.d_name = driver_name,
163	.d_version = D_VERSION,
164};
165
166#define hba_from_dev(dev) \
167	((struct hpt_iop_hba *)devclass_get_softc(hptiop_devclass, dev2unit(dev)))
168
169#define BUS_SPACE_WRT4_ITL(offset, value) bus_space_write_4(hba->bar0t,\
170		hba->bar0h, offsetof(struct hpt_iopmu_itl, offset), (value))
171#define BUS_SPACE_RD4_ITL(offset) bus_space_read_4(hba->bar0t,\
172		hba->bar0h, offsetof(struct hpt_iopmu_itl, offset))
173
174#define BUS_SPACE_WRT4_MV0(offset, value) bus_space_write_4(hba->bar0t,\
175		hba->bar0h, offsetof(struct hpt_iopmv_regs, offset), value)
176#define BUS_SPACE_RD4_MV0(offset) bus_space_read_4(hba->bar0t,\
177		hba->bar0h, offsetof(struct hpt_iopmv_regs, offset))
178#define BUS_SPACE_WRT4_MV2(offset, value) bus_space_write_4(hba->bar2t,\
179		hba->bar2h, offsetof(struct hpt_iopmu_mv, offset), value)
180#define BUS_SPACE_RD4_MV2(offset) bus_space_read_4(hba->bar2t,\
181		hba->bar2h, offsetof(struct hpt_iopmu_mv, offset))
182
183#define BUS_SPACE_WRT4_MVFREY2(offset, value) bus_space_write_4(hba->bar2t,\
184		hba->bar2h, offsetof(struct hpt_iopmu_mvfrey, offset), value)
185#define BUS_SPACE_RD4_MVFREY2(offset) bus_space_read_4(hba->bar2t,\
186		hba->bar2h, offsetof(struct hpt_iopmu_mvfrey, offset))
187
188static int hptiop_open(ioctl_dev_t dev, int flags,
189					int devtype, ioctl_thread_t proc)
190{
191	struct hpt_iop_hba *hba = hba_from_dev(dev);
192
193	if (hba==NULL)
194		return ENXIO;
195	if (hba->flag & HPT_IOCTL_FLAG_OPEN)
196		return EBUSY;
197	hba->flag |= HPT_IOCTL_FLAG_OPEN;
198	return 0;
199}
200
201static int hptiop_close(ioctl_dev_t dev, int flags,
202					int devtype, ioctl_thread_t proc)
203{
204	struct hpt_iop_hba *hba = hba_from_dev(dev);
205	hba->flag &= ~(u_int32_t)HPT_IOCTL_FLAG_OPEN;
206	return 0;
207}
208
209static int hptiop_ioctl(ioctl_dev_t dev, u_long cmd, caddr_t data,
210					int flags, ioctl_thread_t proc)
211{
212	int ret = EFAULT;
213	struct hpt_iop_hba *hba = hba_from_dev(dev);
214
215	mtx_lock(&Giant);
216
217	switch (cmd) {
218	case HPT_DO_IOCONTROL:
219		ret = hba->ops->do_ioctl(hba,
220				(struct hpt_iop_ioctl_param *)data);
221		break;
222	case HPT_SCAN_BUS:
223		ret = hptiop_rescan_bus(hba);
224		break;
225	}
226
227	mtx_unlock(&Giant);
228
229	return ret;
230}
231
232static u_int64_t hptiop_mv_outbound_read(struct hpt_iop_hba *hba)
233{
234	u_int64_t p;
235	u_int32_t outbound_tail = BUS_SPACE_RD4_MV2(outbound_tail);
236	u_int32_t outbound_head = BUS_SPACE_RD4_MV2(outbound_head);
237
238	if (outbound_tail != outbound_head) {
239		bus_space_read_region_4(hba->bar2t, hba->bar2h,
240			offsetof(struct hpt_iopmu_mv,
241				outbound_q[outbound_tail]),
242			(u_int32_t *)&p, 2);
243
244		outbound_tail++;
245
246		if (outbound_tail == MVIOP_QUEUE_LEN)
247			outbound_tail = 0;
248
249		BUS_SPACE_WRT4_MV2(outbound_tail, outbound_tail);
250		return p;
251	} else
252		return 0;
253}
254
255static void hptiop_mv_inbound_write(u_int64_t p, struct hpt_iop_hba *hba)
256{
257	u_int32_t inbound_head = BUS_SPACE_RD4_MV2(inbound_head);
258	u_int32_t head = inbound_head + 1;
259
260	if (head == MVIOP_QUEUE_LEN)
261		head = 0;
262
263	bus_space_write_region_4(hba->bar2t, hba->bar2h,
264			offsetof(struct hpt_iopmu_mv, inbound_q[inbound_head]),
265			(u_int32_t *)&p, 2);
266	BUS_SPACE_WRT4_MV2(inbound_head, head);
267	BUS_SPACE_WRT4_MV0(inbound_doorbell, MVIOP_MU_INBOUND_INT_POSTQUEUE);
268}
269
270static void hptiop_post_msg_itl(struct hpt_iop_hba *hba, u_int32_t msg)
271{
272	BUS_SPACE_WRT4_ITL(inbound_msgaddr0, msg);
273	BUS_SPACE_RD4_ITL(outbound_intstatus);
274}
275
276static void hptiop_post_msg_mv(struct hpt_iop_hba *hba, u_int32_t msg)
277{
278
279	BUS_SPACE_WRT4_MV2(inbound_msg, msg);
280	BUS_SPACE_WRT4_MV0(inbound_doorbell, MVIOP_MU_INBOUND_INT_MSG);
281
282	BUS_SPACE_RD4_MV0(outbound_intmask);
283}
284
285static void hptiop_post_msg_mvfrey(struct hpt_iop_hba *hba, u_int32_t msg)
286{
287	BUS_SPACE_WRT4_MVFREY2(f0_to_cpu_msg_a, msg);
288	BUS_SPACE_RD4_MVFREY2(f0_to_cpu_msg_a);
289}
290
291static int hptiop_wait_ready_itl(struct hpt_iop_hba * hba, u_int32_t millisec)
292{
293	u_int32_t req=0;
294	int i;
295
296	for (i = 0; i < millisec; i++) {
297		req = BUS_SPACE_RD4_ITL(inbound_queue);
298		if (req != IOPMU_QUEUE_EMPTY)
299			break;
300		DELAY(1000);
301	}
302
303	if (req!=IOPMU_QUEUE_EMPTY) {
304		BUS_SPACE_WRT4_ITL(outbound_queue, req);
305		BUS_SPACE_RD4_ITL(outbound_intstatus);
306		return 0;
307	}
308
309	return -1;
310}
311
312static int hptiop_wait_ready_mv(struct hpt_iop_hba * hba, u_int32_t millisec)
313{
314	if (hptiop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_NOP, millisec))
315		return -1;
316
317	return 0;
318}
319
320static int hptiop_wait_ready_mvfrey(struct hpt_iop_hba * hba,
321							u_int32_t millisec)
322{
323	if (hptiop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_NOP, millisec))
324		return -1;
325
326	return 0;
327}
328
329static void hptiop_request_callback_itl(struct hpt_iop_hba * hba,
330							u_int32_t index)
331{
332	struct hpt_iop_srb *srb;
333	struct hpt_iop_request_scsi_command *req=NULL;
334	union ccb *ccb;
335	u_int8_t *cdb;
336	u_int32_t result, temp, dxfer;
337	u_int64_t temp64;
338
339	if (index & IOPMU_QUEUE_MASK_HOST_BITS) { /*host req*/
340		if (hba->firmware_version > 0x01020000 ||
341			hba->interface_version > 0x01020000) {
342			srb = hba->srb[index & ~(u_int32_t)
343				(IOPMU_QUEUE_ADDR_HOST_BIT
344				| IOPMU_QUEUE_REQUEST_RESULT_BIT)];
345			req = (struct hpt_iop_request_scsi_command *)srb;
346			if (index & IOPMU_QUEUE_REQUEST_RESULT_BIT)
347				result = IOP_RESULT_SUCCESS;
348			else
349				result = req->header.result;
350		} else {
351			srb = hba->srb[index &
352				~(u_int32_t)IOPMU_QUEUE_ADDR_HOST_BIT];
353			req = (struct hpt_iop_request_scsi_command *)srb;
354			result = req->header.result;
355		}
356		dxfer = req->dataxfer_length;
357		goto srb_complete;
358	}
359
360	/*iop req*/
361	temp = bus_space_read_4(hba->bar0t, hba->bar0h, index +
362		offsetof(struct hpt_iop_request_header, type));
363	result = bus_space_read_4(hba->bar0t, hba->bar0h, index +
364		offsetof(struct hpt_iop_request_header, result));
365	switch(temp) {
366	case IOP_REQUEST_TYPE_IOCTL_COMMAND:
367	{
368		temp64 = 0;
369		bus_space_write_region_4(hba->bar0t, hba->bar0h, index +
370			offsetof(struct hpt_iop_request_header, context),
371			(u_int32_t *)&temp64, 2);
372		wakeup((void *)((unsigned long)hba->u.itl.mu + index));
373		break;
374	}
375
376	case IOP_REQUEST_TYPE_SCSI_COMMAND:
377		bus_space_read_region_4(hba->bar0t, hba->bar0h, index +
378			offsetof(struct hpt_iop_request_header, context),
379			(u_int32_t *)&temp64, 2);
380		srb = (struct hpt_iop_srb *)(unsigned long)temp64;
381		dxfer = bus_space_read_4(hba->bar0t, hba->bar0h,
382				index + offsetof(struct hpt_iop_request_scsi_command,
383				dataxfer_length));
384srb_complete:
385		ccb = (union ccb *)srb->ccb;
386		if (ccb->ccb_h.flags & CAM_CDB_POINTER)
387			cdb = ccb->csio.cdb_io.cdb_ptr;
388		else
389			cdb = ccb->csio.cdb_io.cdb_bytes;
390
391		if (cdb[0] == SYNCHRONIZE_CACHE) { /* ??? */
392			ccb->ccb_h.status = CAM_REQ_CMP;
393			goto scsi_done;
394		}
395
396		switch (result) {
397		case IOP_RESULT_SUCCESS:
398			switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
399			case CAM_DIR_IN:
400				bus_dmamap_sync(hba->io_dmat,
401					srb->dma_map, BUS_DMASYNC_POSTREAD);
402				bus_dmamap_unload(hba->io_dmat, srb->dma_map);
403				break;
404			case CAM_DIR_OUT:
405				bus_dmamap_sync(hba->io_dmat,
406					srb->dma_map, BUS_DMASYNC_POSTWRITE);
407				bus_dmamap_unload(hba->io_dmat, srb->dma_map);
408				break;
409			}
410
411			ccb->ccb_h.status = CAM_REQ_CMP;
412			break;
413
414		case IOP_RESULT_BAD_TARGET:
415			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
416			break;
417		case IOP_RESULT_BUSY:
418			ccb->ccb_h.status = CAM_BUSY;
419			break;
420		case IOP_RESULT_INVALID_REQUEST:
421			ccb->ccb_h.status = CAM_REQ_INVALID;
422			break;
423		case IOP_RESULT_FAIL:
424			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
425			break;
426		case IOP_RESULT_RESET:
427			ccb->ccb_h.status = CAM_BUSY;
428			break;
429		case IOP_RESULT_CHECK_CONDITION:
430			memset(&ccb->csio.sense_data, 0,
431			    sizeof(ccb->csio.sense_data));
432			if (dxfer < ccb->csio.sense_len)
433				ccb->csio.sense_resid = ccb->csio.sense_len -
434				    dxfer;
435			else
436				ccb->csio.sense_resid = 0;
437			if (srb->srb_flag & HPT_SRB_FLAG_HIGH_MEM_ACESS) {/*iop*/
438				bus_space_read_region_1(hba->bar0t, hba->bar0h,
439					index + offsetof(struct hpt_iop_request_scsi_command,
440					sg_list), (u_int8_t *)&ccb->csio.sense_data,
441					MIN(dxfer, sizeof(ccb->csio.sense_data)));
442			} else {
443				memcpy(&ccb->csio.sense_data, &req->sg_list,
444					MIN(dxfer, sizeof(ccb->csio.sense_data)));
445			}
446			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
447			ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
448			ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
449			break;
450		default:
451			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
452			break;
453		}
454scsi_done:
455		if (srb->srb_flag & HPT_SRB_FLAG_HIGH_MEM_ACESS)
456			BUS_SPACE_WRT4_ITL(outbound_queue, index);
457
458		ccb->csio.resid = ccb->csio.dxfer_len - dxfer;
459
460		hptiop_free_srb(hba, srb);
461		xpt_done(ccb);
462		break;
463	}
464}
465
466static void hptiop_drain_outbound_queue_itl(struct hpt_iop_hba *hba)
467{
468	u_int32_t req, temp;
469
470	while ((req = BUS_SPACE_RD4_ITL(outbound_queue)) !=IOPMU_QUEUE_EMPTY) {
471		if (req & IOPMU_QUEUE_MASK_HOST_BITS)
472			hptiop_request_callback_itl(hba, req);
473		else {
474			struct hpt_iop_request_header *p;
475
476			p = (struct hpt_iop_request_header *)
477				((char *)hba->u.itl.mu + req);
478			temp = bus_space_read_4(hba->bar0t,
479					hba->bar0h,req +
480					offsetof(struct hpt_iop_request_header,
481						flags));
482			if (temp & IOP_REQUEST_FLAG_SYNC_REQUEST) {
483				u_int64_t temp64;
484				bus_space_read_region_4(hba->bar0t,
485					hba->bar0h,req +
486					offsetof(struct hpt_iop_request_header,
487						context),
488					(u_int32_t *)&temp64, 2);
489				if (temp64) {
490					hptiop_request_callback_itl(hba, req);
491				} else {
492					temp64 = 1;
493					bus_space_write_region_4(hba->bar0t,
494						hba->bar0h,req +
495						offsetof(struct hpt_iop_request_header,
496							context),
497						(u_int32_t *)&temp64, 2);
498				}
499			} else
500				hptiop_request_callback_itl(hba, req);
501		}
502	}
503}
504
505static int hptiop_intr_itl(struct hpt_iop_hba * hba)
506{
507	u_int32_t status;
508	int ret = 0;
509
510	status = BUS_SPACE_RD4_ITL(outbound_intstatus);
511
512	if (status & IOPMU_OUTBOUND_INT_MSG0) {
513		u_int32_t msg = BUS_SPACE_RD4_ITL(outbound_msgaddr0);
514		KdPrint(("hptiop: received outbound msg %x\n", msg));
515		BUS_SPACE_WRT4_ITL(outbound_intstatus, IOPMU_OUTBOUND_INT_MSG0);
516		hptiop_os_message_callback(hba, msg);
517		ret = 1;
518	}
519
520	if (status & IOPMU_OUTBOUND_INT_POSTQUEUE) {
521		hptiop_drain_outbound_queue_itl(hba);
522		ret = 1;
523	}
524
525	return ret;
526}
527
528static void hptiop_request_callback_mv(struct hpt_iop_hba * hba,
529							u_int64_t _tag)
530{
531	u_int32_t context = (u_int32_t)_tag;
532
533	if (context & MVIOP_CMD_TYPE_SCSI) {
534		struct hpt_iop_srb *srb;
535		struct hpt_iop_request_scsi_command *req;
536		union ccb *ccb;
537		u_int8_t *cdb;
538
539		srb = hba->srb[context >> MVIOP_REQUEST_NUMBER_START_BIT];
540		req = (struct hpt_iop_request_scsi_command *)srb;
541		ccb = (union ccb *)srb->ccb;
542		if (ccb->ccb_h.flags & CAM_CDB_POINTER)
543			cdb = ccb->csio.cdb_io.cdb_ptr;
544		else
545			cdb = ccb->csio.cdb_io.cdb_bytes;
546
547		if (cdb[0] == SYNCHRONIZE_CACHE) { /* ??? */
548			ccb->ccb_h.status = CAM_REQ_CMP;
549			goto scsi_done;
550		}
551		if (context & MVIOP_MU_QUEUE_REQUEST_RESULT_BIT)
552			req->header.result = IOP_RESULT_SUCCESS;
553
554		switch (req->header.result) {
555		case IOP_RESULT_SUCCESS:
556			switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
557			case CAM_DIR_IN:
558				bus_dmamap_sync(hba->io_dmat,
559					srb->dma_map, BUS_DMASYNC_POSTREAD);
560				bus_dmamap_unload(hba->io_dmat, srb->dma_map);
561				break;
562			case CAM_DIR_OUT:
563				bus_dmamap_sync(hba->io_dmat,
564					srb->dma_map, BUS_DMASYNC_POSTWRITE);
565				bus_dmamap_unload(hba->io_dmat, srb->dma_map);
566				break;
567			}
568			ccb->ccb_h.status = CAM_REQ_CMP;
569			break;
570		case IOP_RESULT_BAD_TARGET:
571			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
572			break;
573		case IOP_RESULT_BUSY:
574			ccb->ccb_h.status = CAM_BUSY;
575			break;
576		case IOP_RESULT_INVALID_REQUEST:
577			ccb->ccb_h.status = CAM_REQ_INVALID;
578			break;
579		case IOP_RESULT_FAIL:
580			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
581			break;
582		case IOP_RESULT_RESET:
583			ccb->ccb_h.status = CAM_BUSY;
584			break;
585		case IOP_RESULT_CHECK_CONDITION:
586			memset(&ccb->csio.sense_data, 0,
587			    sizeof(ccb->csio.sense_data));
588			if (req->dataxfer_length < ccb->csio.sense_len)
589				ccb->csio.sense_resid = ccb->csio.sense_len -
590				    req->dataxfer_length;
591			else
592				ccb->csio.sense_resid = 0;
593			memcpy(&ccb->csio.sense_data, &req->sg_list,
594				MIN(req->dataxfer_length, sizeof(ccb->csio.sense_data)));
595			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
596			ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
597			ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
598			break;
599		default:
600			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
601			break;
602		}
603scsi_done:
604		ccb->csio.resid = ccb->csio.dxfer_len - req->dataxfer_length;
605
606		hptiop_free_srb(hba, srb);
607		xpt_done(ccb);
608	} else if (context & MVIOP_CMD_TYPE_IOCTL) {
609		struct hpt_iop_request_ioctl_command *req = hba->ctlcfg_ptr;
610		if (context & MVIOP_MU_QUEUE_REQUEST_RESULT_BIT)
611			hba->config_done = 1;
612		else
613			hba->config_done = -1;
614		wakeup(req);
615	} else if (context &
616			(MVIOP_CMD_TYPE_SET_CONFIG |
617				MVIOP_CMD_TYPE_GET_CONFIG))
618		hba->config_done = 1;
619	else {
620		device_printf(hba->pcidev, "wrong callback type\n");
621	}
622}
623
624static void hptiop_request_callback_mvfrey(struct hpt_iop_hba * hba,
625				u_int32_t _tag)
626{
627	u_int32_t req_type = _tag & 0xf;
628
629	struct hpt_iop_srb *srb;
630	struct hpt_iop_request_scsi_command *req;
631	union ccb *ccb;
632	u_int8_t *cdb;
633
634	switch (req_type) {
635	case IOP_REQUEST_TYPE_GET_CONFIG:
636	case IOP_REQUEST_TYPE_SET_CONFIG:
637		hba->config_done = 1;
638		break;
639
640	case IOP_REQUEST_TYPE_SCSI_COMMAND:
641		srb = hba->srb[(_tag >> 4) & 0xff];
642		req = (struct hpt_iop_request_scsi_command *)srb;
643
644		ccb = (union ccb *)srb->ccb;
645
646		callout_stop(&srb->timeout);
647
648		if (ccb->ccb_h.flags & CAM_CDB_POINTER)
649			cdb = ccb->csio.cdb_io.cdb_ptr;
650		else
651			cdb = ccb->csio.cdb_io.cdb_bytes;
652
653		if (cdb[0] == SYNCHRONIZE_CACHE) { /* ??? */
654			ccb->ccb_h.status = CAM_REQ_CMP;
655			goto scsi_done;
656		}
657
658		if (_tag & MVFREYIOPMU_QUEUE_REQUEST_RESULT_BIT)
659			req->header.result = IOP_RESULT_SUCCESS;
660
661		switch (req->header.result) {
662		case IOP_RESULT_SUCCESS:
663			switch (ccb->ccb_h.flags & CAM_DIR_MASK) {
664			case CAM_DIR_IN:
665				bus_dmamap_sync(hba->io_dmat,
666						srb->dma_map, BUS_DMASYNC_POSTREAD);
667				bus_dmamap_unload(hba->io_dmat, srb->dma_map);
668				break;
669			case CAM_DIR_OUT:
670				bus_dmamap_sync(hba->io_dmat,
671						srb->dma_map, BUS_DMASYNC_POSTWRITE);
672				bus_dmamap_unload(hba->io_dmat, srb->dma_map);
673				break;
674			}
675			ccb->ccb_h.status = CAM_REQ_CMP;
676			break;
677		case IOP_RESULT_BAD_TARGET:
678			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
679			break;
680		case IOP_RESULT_BUSY:
681			ccb->ccb_h.status = CAM_BUSY;
682			break;
683		case IOP_RESULT_INVALID_REQUEST:
684			ccb->ccb_h.status = CAM_REQ_INVALID;
685			break;
686		case IOP_RESULT_FAIL:
687			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
688			break;
689		case IOP_RESULT_RESET:
690			ccb->ccb_h.status = CAM_BUSY;
691			break;
692		case IOP_RESULT_CHECK_CONDITION:
693			memset(&ccb->csio.sense_data, 0,
694			       sizeof(ccb->csio.sense_data));
695			if (req->dataxfer_length < ccb->csio.sense_len)
696				ccb->csio.sense_resid = ccb->csio.sense_len -
697				req->dataxfer_length;
698			else
699				ccb->csio.sense_resid = 0;
700			memcpy(&ccb->csio.sense_data, &req->sg_list,
701			       MIN(req->dataxfer_length, sizeof(ccb->csio.sense_data)));
702			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
703			ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
704			ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
705			break;
706		default:
707			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
708			break;
709		}
710scsi_done:
711		ccb->csio.resid = ccb->csio.dxfer_len - req->dataxfer_length;
712
713		hptiop_free_srb(hba, srb);
714		xpt_done(ccb);
715		break;
716	case IOP_REQUEST_TYPE_IOCTL_COMMAND:
717		if (_tag & MVFREYIOPMU_QUEUE_REQUEST_RESULT_BIT)
718			hba->config_done = 1;
719		else
720			hba->config_done = -1;
721		wakeup((struct hpt_iop_request_ioctl_command *)hba->ctlcfg_ptr);
722		break;
723	default:
724		device_printf(hba->pcidev, "wrong callback type\n");
725		break;
726	}
727}
728
729static void hptiop_drain_outbound_queue_mv(struct hpt_iop_hba * hba)
730{
731	u_int64_t req;
732
733	while ((req = hptiop_mv_outbound_read(hba))) {
734		if (req & MVIOP_MU_QUEUE_ADDR_HOST_BIT) {
735			if (req & MVIOP_MU_QUEUE_REQUEST_RETURN_CONTEXT) {
736				hptiop_request_callback_mv(hba, req);
737			}
738	    	}
739	}
740}
741
742static int hptiop_intr_mv(struct hpt_iop_hba * hba)
743{
744	u_int32_t status;
745	int ret = 0;
746
747	status = BUS_SPACE_RD4_MV0(outbound_doorbell);
748
749	if (status)
750		BUS_SPACE_WRT4_MV0(outbound_doorbell, ~status);
751
752	if (status & MVIOP_MU_OUTBOUND_INT_MSG) {
753		u_int32_t msg = BUS_SPACE_RD4_MV2(outbound_msg);
754		KdPrint(("hptiop: received outbound msg %x\n", msg));
755		hptiop_os_message_callback(hba, msg);
756		ret = 1;
757	}
758
759	if (status & MVIOP_MU_OUTBOUND_INT_POSTQUEUE) {
760		hptiop_drain_outbound_queue_mv(hba);
761		ret = 1;
762	}
763
764	return ret;
765}
766
767static int hptiop_intr_mvfrey(struct hpt_iop_hba * hba)
768{
769	u_int32_t status, _tag, cptr;
770	int ret = 0;
771
772	if (hba->initialized) {
773		BUS_SPACE_WRT4_MVFREY2(pcie_f0_int_enable, 0);
774	}
775
776	status = BUS_SPACE_RD4_MVFREY2(f0_doorbell);
777	if (status) {
778		BUS_SPACE_WRT4_MVFREY2(f0_doorbell, status);
779		if (status & CPU_TO_F0_DRBL_MSG_A_BIT) {
780			u_int32_t msg = BUS_SPACE_RD4_MVFREY2(cpu_to_f0_msg_a);
781			hptiop_os_message_callback(hba, msg);
782		}
783		ret = 1;
784	}
785
786	status = BUS_SPACE_RD4_MVFREY2(isr_cause);
787	if (status) {
788		BUS_SPACE_WRT4_MVFREY2(isr_cause, status);
789		do {
790			cptr = *hba->u.mvfrey.outlist_cptr & 0xff;
791			while (hba->u.mvfrey.outlist_rptr != cptr) {
792				hba->u.mvfrey.outlist_rptr++;
793				if (hba->u.mvfrey.outlist_rptr == hba->u.mvfrey.list_count) {
794					hba->u.mvfrey.outlist_rptr = 0;
795				}
796
797				_tag = hba->u.mvfrey.outlist[hba->u.mvfrey.outlist_rptr].val;
798				hptiop_request_callback_mvfrey(hba, _tag);
799				ret = 2;
800			}
801		} while (cptr != (*hba->u.mvfrey.outlist_cptr & 0xff));
802	}
803
804	if (hba->initialized) {
805		BUS_SPACE_WRT4_MVFREY2(pcie_f0_int_enable, 0x1010);
806	}
807
808	return ret;
809}
810
811static int hptiop_send_sync_request_itl(struct hpt_iop_hba * hba,
812					u_int32_t req32, u_int32_t millisec)
813{
814	u_int32_t i;
815	u_int64_t temp64;
816
817	BUS_SPACE_WRT4_ITL(inbound_queue, req32);
818	BUS_SPACE_RD4_ITL(outbound_intstatus);
819
820	for (i = 0; i < millisec; i++) {
821		hptiop_intr_itl(hba);
822		bus_space_read_region_4(hba->bar0t, hba->bar0h, req32 +
823			offsetof(struct hpt_iop_request_header, context),
824			(u_int32_t *)&temp64, 2);
825		if (temp64)
826			return 0;
827		DELAY(1000);
828	}
829
830	return -1;
831}
832
833static int hptiop_send_sync_request_mv(struct hpt_iop_hba *hba,
834					void *req, u_int32_t millisec)
835{
836	u_int32_t i;
837	u_int64_t phy_addr;
838	hba->config_done = 0;
839
840	phy_addr = hba->ctlcfgcmd_phy |
841			(u_int64_t)MVIOP_MU_QUEUE_ADDR_HOST_BIT;
842	((struct hpt_iop_request_get_config *)req)->header.flags |=
843		IOP_REQUEST_FLAG_SYNC_REQUEST |
844		IOP_REQUEST_FLAG_OUTPUT_CONTEXT;
845	hptiop_mv_inbound_write(phy_addr, hba);
846	BUS_SPACE_RD4_MV0(outbound_intmask);
847
848	for (i = 0; i < millisec; i++) {
849		hptiop_intr_mv(hba);
850		if (hba->config_done)
851			return 0;
852		DELAY(1000);
853	}
854	return -1;
855}
856
857static int hptiop_send_sync_request_mvfrey(struct hpt_iop_hba *hba,
858					void *req, u_int32_t millisec)
859{
860	u_int32_t i, index;
861	u_int64_t phy_addr;
862	struct hpt_iop_request_header *reqhdr =
863										(struct hpt_iop_request_header *)req;
864
865	hba->config_done = 0;
866
867	phy_addr = hba->ctlcfgcmd_phy;
868	reqhdr->flags = IOP_REQUEST_FLAG_SYNC_REQUEST
869					| IOP_REQUEST_FLAG_OUTPUT_CONTEXT
870					| IOP_REQUEST_FLAG_ADDR_BITS
871					| ((phy_addr >> 16) & 0xffff0000);
872	reqhdr->context = ((phy_addr & 0xffffffff) << 32 )
873					| IOPMU_QUEUE_ADDR_HOST_BIT | reqhdr->type;
874
875	hba->u.mvfrey.inlist_wptr++;
876	index = hba->u.mvfrey.inlist_wptr & 0x3fff;
877
878	if (index == hba->u.mvfrey.list_count) {
879		index = 0;
880		hba->u.mvfrey.inlist_wptr &= ~0x3fff;
881		hba->u.mvfrey.inlist_wptr ^= CL_POINTER_TOGGLE;
882	}
883
884	hba->u.mvfrey.inlist[index].addr = phy_addr;
885	hba->u.mvfrey.inlist[index].intrfc_len = (reqhdr->size + 3) / 4;
886
887	BUS_SPACE_WRT4_MVFREY2(inbound_write_ptr, hba->u.mvfrey.inlist_wptr);
888	BUS_SPACE_RD4_MVFREY2(inbound_write_ptr);
889
890	for (i = 0; i < millisec; i++) {
891		hptiop_intr_mvfrey(hba);
892		if (hba->config_done)
893			return 0;
894		DELAY(1000);
895	}
896	return -1;
897}
898
899static int hptiop_send_sync_msg(struct hpt_iop_hba *hba,
900					u_int32_t msg, u_int32_t millisec)
901{
902	u_int32_t i;
903
904	hba->msg_done = 0;
905	hba->ops->post_msg(hba, msg);
906
907	for (i=0; i<millisec; i++) {
908		hba->ops->iop_intr(hba);
909		if (hba->msg_done)
910			break;
911		DELAY(1000);
912	}
913
914	return hba->msg_done? 0 : -1;
915}
916
917static int hptiop_get_config_itl(struct hpt_iop_hba * hba,
918				struct hpt_iop_request_get_config * config)
919{
920	u_int32_t req32;
921
922	config->header.size = sizeof(struct hpt_iop_request_get_config);
923	config->header.type = IOP_REQUEST_TYPE_GET_CONFIG;
924	config->header.flags = IOP_REQUEST_FLAG_SYNC_REQUEST;
925	config->header.result = IOP_RESULT_PENDING;
926	config->header.context = 0;
927
928	req32 = BUS_SPACE_RD4_ITL(inbound_queue);
929	if (req32 == IOPMU_QUEUE_EMPTY)
930		return -1;
931
932	bus_space_write_region_4(hba->bar0t, hba->bar0h,
933			req32, (u_int32_t *)config,
934			sizeof(struct hpt_iop_request_header) >> 2);
935
936	if (hptiop_send_sync_request_itl(hba, req32, 20000)) {
937		KdPrint(("hptiop: get config send cmd failed"));
938		return -1;
939	}
940
941	bus_space_read_region_4(hba->bar0t, hba->bar0h,
942			req32, (u_int32_t *)config,
943			sizeof(struct hpt_iop_request_get_config) >> 2);
944
945	BUS_SPACE_WRT4_ITL(outbound_queue, req32);
946
947	return 0;
948}
949
950static int hptiop_get_config_mv(struct hpt_iop_hba * hba,
951				struct hpt_iop_request_get_config * config)
952{
953	struct hpt_iop_request_get_config *req;
954
955	if (!(req = hba->ctlcfg_ptr))
956		return -1;
957
958	req->header.flags = 0;
959	req->header.type = IOP_REQUEST_TYPE_GET_CONFIG;
960	req->header.size = sizeof(struct hpt_iop_request_get_config);
961	req->header.result = IOP_RESULT_PENDING;
962	req->header.context = MVIOP_CMD_TYPE_GET_CONFIG;
963
964	if (hptiop_send_sync_request_mv(hba, req, 20000)) {
965		KdPrint(("hptiop: get config send cmd failed"));
966		return -1;
967	}
968
969	*config = *req;
970	return 0;
971}
972
973static int hptiop_get_config_mvfrey(struct hpt_iop_hba * hba,
974				struct hpt_iop_request_get_config * config)
975{
976	struct hpt_iop_request_get_config *info = hba->u.mvfrey.config;
977
978	if (info->header.size != sizeof(struct hpt_iop_request_get_config) ||
979	    info->header.type != IOP_REQUEST_TYPE_GET_CONFIG) {
980		KdPrint(("hptiop: header size %x/%x type %x/%x",
981			 info->header.size, (int)sizeof(struct hpt_iop_request_get_config),
982			 info->header.type, IOP_REQUEST_TYPE_GET_CONFIG));
983		return -1;
984	}
985
986	config->interface_version = info->interface_version;
987	config->firmware_version = info->firmware_version;
988	config->max_requests = info->max_requests;
989	config->request_size = info->request_size;
990	config->max_sg_count = info->max_sg_count;
991	config->data_transfer_length = info->data_transfer_length;
992	config->alignment_mask = info->alignment_mask;
993	config->max_devices = info->max_devices;
994	config->sdram_size = info->sdram_size;
995
996	KdPrint(("hptiop: maxreq %x reqsz %x datalen %x maxdev %x sdram %x",
997		 config->max_requests, config->request_size,
998		 config->data_transfer_length, config->max_devices,
999		 config->sdram_size));
1000
1001	return 0;
1002}
1003
1004static int hptiop_set_config_itl(struct hpt_iop_hba *hba,
1005				struct hpt_iop_request_set_config *config)
1006{
1007	u_int32_t req32;
1008
1009	req32 = BUS_SPACE_RD4_ITL(inbound_queue);
1010
1011	if (req32 == IOPMU_QUEUE_EMPTY)
1012		return -1;
1013
1014	config->header.size = sizeof(struct hpt_iop_request_set_config);
1015	config->header.type = IOP_REQUEST_TYPE_SET_CONFIG;
1016	config->header.flags = IOP_REQUEST_FLAG_SYNC_REQUEST;
1017	config->header.result = IOP_RESULT_PENDING;
1018	config->header.context = 0;
1019
1020	bus_space_write_region_4(hba->bar0t, hba->bar0h, req32,
1021		(u_int32_t *)config,
1022		sizeof(struct hpt_iop_request_set_config) >> 2);
1023
1024	if (hptiop_send_sync_request_itl(hba, req32, 20000)) {
1025		KdPrint(("hptiop: set config send cmd failed"));
1026		return -1;
1027	}
1028
1029	BUS_SPACE_WRT4_ITL(outbound_queue, req32);
1030
1031	return 0;
1032}
1033
1034static int hptiop_set_config_mv(struct hpt_iop_hba *hba,
1035				struct hpt_iop_request_set_config *config)
1036{
1037	struct hpt_iop_request_set_config *req;
1038
1039	if (!(req = hba->ctlcfg_ptr))
1040		return -1;
1041
1042	memcpy((u_int8_t *)req + sizeof(struct hpt_iop_request_header),
1043		(u_int8_t *)config + sizeof(struct hpt_iop_request_header),
1044		sizeof(struct hpt_iop_request_set_config) -
1045			sizeof(struct hpt_iop_request_header));
1046
1047	req->header.flags = 0;
1048	req->header.type = IOP_REQUEST_TYPE_SET_CONFIG;
1049	req->header.size = sizeof(struct hpt_iop_request_set_config);
1050	req->header.result = IOP_RESULT_PENDING;
1051	req->header.context = MVIOP_CMD_TYPE_SET_CONFIG;
1052
1053	if (hptiop_send_sync_request_mv(hba, req, 20000)) {
1054		KdPrint(("hptiop: set config send cmd failed"));
1055		return -1;
1056	}
1057
1058	return 0;
1059}
1060
1061static int hptiop_set_config_mvfrey(struct hpt_iop_hba *hba,
1062				struct hpt_iop_request_set_config *config)
1063{
1064	struct hpt_iop_request_set_config *req;
1065
1066	if (!(req = hba->ctlcfg_ptr))
1067		return -1;
1068
1069	memcpy((u_int8_t *)req + sizeof(struct hpt_iop_request_header),
1070		(u_int8_t *)config + sizeof(struct hpt_iop_request_header),
1071		sizeof(struct hpt_iop_request_set_config) -
1072			sizeof(struct hpt_iop_request_header));
1073
1074	req->header.type = IOP_REQUEST_TYPE_SET_CONFIG;
1075	req->header.size = sizeof(struct hpt_iop_request_set_config);
1076	req->header.result = IOP_RESULT_PENDING;
1077
1078	if (hptiop_send_sync_request_mvfrey(hba, req, 20000)) {
1079		KdPrint(("hptiop: set config send cmd failed"));
1080		return -1;
1081	}
1082
1083	return 0;
1084}
1085
1086static int hptiop_post_ioctl_command_itl(struct hpt_iop_hba *hba,
1087				u_int32_t req32,
1088				struct hpt_iop_ioctl_param *pParams)
1089{
1090	u_int64_t temp64;
1091	struct hpt_iop_request_ioctl_command req;
1092
1093	if ((((pParams->nInBufferSize + 3) & ~3) + pParams->nOutBufferSize) >
1094			(hba->max_request_size -
1095			offsetof(struct hpt_iop_request_ioctl_command, buf))) {
1096		device_printf(hba->pcidev, "request size beyond max value");
1097		return -1;
1098	}
1099
1100	req.header.size = offsetof(struct hpt_iop_request_ioctl_command, buf)
1101		+ pParams->nInBufferSize;
1102	req.header.type = IOP_REQUEST_TYPE_IOCTL_COMMAND;
1103	req.header.flags = IOP_REQUEST_FLAG_SYNC_REQUEST;
1104	req.header.result = IOP_RESULT_PENDING;
1105	req.header.context = req32 + (u_int64_t)(unsigned long)hba->u.itl.mu;
1106	req.ioctl_code = HPT_CTL_CODE_BSD_TO_IOP(pParams->dwIoControlCode);
1107	req.inbuf_size = pParams->nInBufferSize;
1108	req.outbuf_size = pParams->nOutBufferSize;
1109	req.bytes_returned = 0;
1110
1111	bus_space_write_region_4(hba->bar0t, hba->bar0h, req32, (u_int32_t *)&req,
1112		offsetof(struct hpt_iop_request_ioctl_command, buf)>>2);
1113
1114	hptiop_lock_adapter(hba);
1115
1116	BUS_SPACE_WRT4_ITL(inbound_queue, req32);
1117	BUS_SPACE_RD4_ITL(outbound_intstatus);
1118
1119	bus_space_read_region_4(hba->bar0t, hba->bar0h, req32 +
1120		offsetof(struct hpt_iop_request_ioctl_command, header.context),
1121		(u_int32_t *)&temp64, 2);
1122	while (temp64) {
1123		if (hptiop_sleep(hba, (void *)((unsigned long)hba->u.itl.mu + req32),
1124				PPAUSE, "hptctl", HPT_OSM_TIMEOUT)==0)
1125			break;
1126		hptiop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_RESET, 60000);
1127		bus_space_read_region_4(hba->bar0t, hba->bar0h,req32 +
1128			offsetof(struct hpt_iop_request_ioctl_command,
1129				header.context),
1130			(u_int32_t *)&temp64, 2);
1131	}
1132
1133	hptiop_unlock_adapter(hba);
1134	return 0;
1135}
1136
1137static int hptiop_bus_space_copyin(struct hpt_iop_hba *hba, u_int32_t bus,
1138									void *user, int size)
1139{
1140	unsigned char byte;
1141	int i;
1142
1143	for (i=0; i<size; i++) {
1144		if (copyin((u_int8_t *)user + i, &byte, 1))
1145			return -1;
1146		bus_space_write_1(hba->bar0t, hba->bar0h, bus + i, byte);
1147	}
1148
1149	return 0;
1150}
1151
1152static int hptiop_bus_space_copyout(struct hpt_iop_hba *hba, u_int32_t bus,
1153									void *user, int size)
1154{
1155	unsigned char byte;
1156	int i;
1157
1158	for (i=0; i<size; i++) {
1159		byte = bus_space_read_1(hba->bar0t, hba->bar0h, bus + i);
1160		if (copyout(&byte, (u_int8_t *)user + i, 1))
1161			return -1;
1162	}
1163
1164	return 0;
1165}
1166
1167static int hptiop_do_ioctl_itl(struct hpt_iop_hba *hba,
1168				struct hpt_iop_ioctl_param * pParams)
1169{
1170	u_int32_t req32;
1171	u_int32_t result;
1172
1173	if ((pParams->Magic != HPT_IOCTL_MAGIC) &&
1174		(pParams->Magic != HPT_IOCTL_MAGIC32))
1175		return EFAULT;
1176
1177	req32 = BUS_SPACE_RD4_ITL(inbound_queue);
1178	if (req32 == IOPMU_QUEUE_EMPTY)
1179		return EFAULT;
1180
1181	if (pParams->nInBufferSize)
1182		if (hptiop_bus_space_copyin(hba, req32 +
1183			offsetof(struct hpt_iop_request_ioctl_command, buf),
1184			(void *)pParams->lpInBuffer, pParams->nInBufferSize))
1185			goto invalid;
1186
1187	if (hptiop_post_ioctl_command_itl(hba, req32, pParams))
1188		goto invalid;
1189
1190	result = bus_space_read_4(hba->bar0t, hba->bar0h, req32 +
1191			offsetof(struct hpt_iop_request_ioctl_command,
1192				header.result));
1193
1194	if (result == IOP_RESULT_SUCCESS) {
1195		if (pParams->nOutBufferSize)
1196			if (hptiop_bus_space_copyout(hba, req32 +
1197				offsetof(struct hpt_iop_request_ioctl_command, buf) +
1198					((pParams->nInBufferSize + 3) & ~3),
1199				(void *)pParams->lpOutBuffer, pParams->nOutBufferSize))
1200				goto invalid;
1201
1202		if (pParams->lpBytesReturned) {
1203			if (hptiop_bus_space_copyout(hba, req32 +
1204				offsetof(struct hpt_iop_request_ioctl_command, bytes_returned),
1205				(void *)pParams->lpBytesReturned, sizeof(unsigned  long)))
1206				goto invalid;
1207		}
1208
1209		BUS_SPACE_WRT4_ITL(outbound_queue, req32);
1210
1211		return 0;
1212	} else{
1213invalid:
1214		BUS_SPACE_WRT4_ITL(outbound_queue, req32);
1215
1216		return EFAULT;
1217	}
1218}
1219
1220static int hptiop_post_ioctl_command_mv(struct hpt_iop_hba *hba,
1221				struct hpt_iop_request_ioctl_command *req,
1222				struct hpt_iop_ioctl_param *pParams)
1223{
1224	u_int64_t req_phy;
1225	int size = 0;
1226
1227	if ((((pParams->nInBufferSize + 3) & ~3) + pParams->nOutBufferSize) >
1228			(hba->max_request_size -
1229			offsetof(struct hpt_iop_request_ioctl_command, buf))) {
1230		device_printf(hba->pcidev, "request size beyond max value");
1231		return -1;
1232	}
1233
1234	req->ioctl_code = HPT_CTL_CODE_BSD_TO_IOP(pParams->dwIoControlCode);
1235	req->inbuf_size = pParams->nInBufferSize;
1236	req->outbuf_size = pParams->nOutBufferSize;
1237	req->header.size = offsetof(struct hpt_iop_request_ioctl_command, buf)
1238					+ pParams->nInBufferSize;
1239	req->header.context = (u_int64_t)MVIOP_CMD_TYPE_IOCTL;
1240	req->header.type = IOP_REQUEST_TYPE_IOCTL_COMMAND;
1241	req->header.result = IOP_RESULT_PENDING;
1242	req->header.flags = IOP_REQUEST_FLAG_OUTPUT_CONTEXT;
1243	size = req->header.size >> 8;
1244	size = imin(3, size);
1245	req_phy = hba->ctlcfgcmd_phy | MVIOP_MU_QUEUE_ADDR_HOST_BIT | size;
1246	hptiop_mv_inbound_write(req_phy, hba);
1247
1248	BUS_SPACE_RD4_MV0(outbound_intmask);
1249
1250	while (hba->config_done == 0) {
1251		if (hptiop_sleep(hba, req, PPAUSE,
1252			"hptctl", HPT_OSM_TIMEOUT)==0)
1253			continue;
1254		hptiop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_RESET, 60000);
1255	}
1256	return 0;
1257}
1258
1259static int hptiop_do_ioctl_mv(struct hpt_iop_hba *hba,
1260				struct hpt_iop_ioctl_param *pParams)
1261{
1262	struct hpt_iop_request_ioctl_command *req;
1263
1264	if ((pParams->Magic != HPT_IOCTL_MAGIC) &&
1265		(pParams->Magic != HPT_IOCTL_MAGIC32))
1266		return EFAULT;
1267
1268	req = (struct hpt_iop_request_ioctl_command *)(hba->ctlcfg_ptr);
1269	hba->config_done = 0;
1270	hptiop_lock_adapter(hba);
1271	if (pParams->nInBufferSize)
1272		if (copyin((void *)pParams->lpInBuffer,
1273				req->buf, pParams->nInBufferSize))
1274			goto invalid;
1275	if (hptiop_post_ioctl_command_mv(hba, req, pParams))
1276		goto invalid;
1277
1278	if (hba->config_done == 1) {
1279		if (pParams->nOutBufferSize)
1280			if (copyout(req->buf +
1281				((pParams->nInBufferSize + 3) & ~3),
1282				(void *)pParams->lpOutBuffer,
1283				pParams->nOutBufferSize))
1284				goto invalid;
1285
1286		if (pParams->lpBytesReturned)
1287			if (copyout(&req->bytes_returned,
1288				(void*)pParams->lpBytesReturned,
1289				sizeof(u_int32_t)))
1290				goto invalid;
1291		hptiop_unlock_adapter(hba);
1292		return 0;
1293	} else{
1294invalid:
1295		hptiop_unlock_adapter(hba);
1296		return EFAULT;
1297	}
1298}
1299
1300static int hptiop_post_ioctl_command_mvfrey(struct hpt_iop_hba *hba,
1301				struct hpt_iop_request_ioctl_command *req,
1302				struct hpt_iop_ioctl_param *pParams)
1303{
1304	u_int64_t phy_addr;
1305	u_int32_t index;
1306
1307	phy_addr = hba->ctlcfgcmd_phy;
1308
1309	if ((((pParams->nInBufferSize + 3) & ~3) + pParams->nOutBufferSize) >
1310			(hba->max_request_size -
1311			offsetof(struct hpt_iop_request_ioctl_command, buf))) {
1312		device_printf(hba->pcidev, "request size beyond max value");
1313		return -1;
1314	}
1315
1316	req->ioctl_code = HPT_CTL_CODE_BSD_TO_IOP(pParams->dwIoControlCode);
1317	req->inbuf_size = pParams->nInBufferSize;
1318	req->outbuf_size = pParams->nOutBufferSize;
1319	req->header.size = offsetof(struct hpt_iop_request_ioctl_command, buf)
1320					+ pParams->nInBufferSize;
1321
1322	req->header.type = IOP_REQUEST_TYPE_IOCTL_COMMAND;
1323	req->header.result = IOP_RESULT_PENDING;
1324
1325	req->header.flags = IOP_REQUEST_FLAG_SYNC_REQUEST
1326						| IOP_REQUEST_FLAG_OUTPUT_CONTEXT
1327						| IOP_REQUEST_FLAG_ADDR_BITS
1328						| ((phy_addr >> 16) & 0xffff0000);
1329	req->header.context = ((phy_addr & 0xffffffff) << 32 )
1330						| IOPMU_QUEUE_ADDR_HOST_BIT | req->header.type;
1331
1332	hba->u.mvfrey.inlist_wptr++;
1333	index = hba->u.mvfrey.inlist_wptr & 0x3fff;
1334
1335	if (index == hba->u.mvfrey.list_count) {
1336		index = 0;
1337		hba->u.mvfrey.inlist_wptr &= ~0x3fff;
1338		hba->u.mvfrey.inlist_wptr ^= CL_POINTER_TOGGLE;
1339	}
1340
1341	hba->u.mvfrey.inlist[index].addr = phy_addr;
1342	hba->u.mvfrey.inlist[index].intrfc_len = (req->header.size + 3) / 4;
1343
1344	BUS_SPACE_WRT4_MVFREY2(inbound_write_ptr, hba->u.mvfrey.inlist_wptr);
1345	BUS_SPACE_RD4_MVFREY2(inbound_write_ptr);
1346
1347	while (hba->config_done == 0) {
1348		if (hptiop_sleep(hba, req, PPAUSE,
1349			"hptctl", HPT_OSM_TIMEOUT)==0)
1350			continue;
1351		hptiop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_RESET, 60000);
1352	}
1353	return 0;
1354}
1355
1356static int hptiop_do_ioctl_mvfrey(struct hpt_iop_hba *hba,
1357				struct hpt_iop_ioctl_param *pParams)
1358{
1359	struct hpt_iop_request_ioctl_command *req;
1360
1361	if ((pParams->Magic != HPT_IOCTL_MAGIC) &&
1362		(pParams->Magic != HPT_IOCTL_MAGIC32))
1363		return EFAULT;
1364
1365	req = (struct hpt_iop_request_ioctl_command *)(hba->ctlcfg_ptr);
1366	hba->config_done = 0;
1367	hptiop_lock_adapter(hba);
1368	if (pParams->nInBufferSize)
1369		if (copyin((void *)pParams->lpInBuffer,
1370				req->buf, pParams->nInBufferSize))
1371			goto invalid;
1372	if (hptiop_post_ioctl_command_mvfrey(hba, req, pParams))
1373		goto invalid;
1374
1375	if (hba->config_done == 1) {
1376		if (pParams->nOutBufferSize)
1377			if (copyout(req->buf +
1378				((pParams->nInBufferSize + 3) & ~3),
1379				(void *)pParams->lpOutBuffer,
1380				pParams->nOutBufferSize))
1381				goto invalid;
1382
1383		if (pParams->lpBytesReturned)
1384			if (copyout(&req->bytes_returned,
1385				(void*)pParams->lpBytesReturned,
1386				sizeof(u_int32_t)))
1387				goto invalid;
1388		hptiop_unlock_adapter(hba);
1389		return 0;
1390	} else{
1391invalid:
1392		hptiop_unlock_adapter(hba);
1393		return EFAULT;
1394	}
1395}
1396
1397static int  hptiop_rescan_bus(struct hpt_iop_hba * hba)
1398{
1399	union ccb           *ccb;
1400
1401	if ((ccb = xpt_alloc_ccb()) == NULL)
1402		return(ENOMEM);
1403	if (xpt_create_path(&ccb->ccb_h.path, NULL, cam_sim_path(hba->sim),
1404		CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
1405		xpt_free_ccb(ccb);
1406		return(EIO);
1407	}
1408	xpt_rescan(ccb);
1409	return(0);
1410}
1411
1412static  bus_dmamap_callback_t   hptiop_map_srb;
1413static  bus_dmamap_callback_t   hptiop_post_scsi_command;
1414static  bus_dmamap_callback_t   hptiop_mv_map_ctlcfg;
1415static	bus_dmamap_callback_t	hptiop_mvfrey_map_ctlcfg;
1416
1417static int hptiop_alloc_pci_res_itl(struct hpt_iop_hba *hba)
1418{
1419	hba->bar0_rid = 0x10;
1420	hba->bar0_res = bus_alloc_resource_any(hba->pcidev,
1421			SYS_RES_MEMORY, &hba->bar0_rid, RF_ACTIVE);
1422
1423	if (hba->bar0_res == NULL) {
1424		device_printf(hba->pcidev,
1425			"failed to get iop base adrress.\n");
1426		return -1;
1427	}
1428	hba->bar0t = rman_get_bustag(hba->bar0_res);
1429	hba->bar0h = rman_get_bushandle(hba->bar0_res);
1430	hba->u.itl.mu = (struct hpt_iopmu_itl *)
1431				rman_get_virtual(hba->bar0_res);
1432
1433	if (!hba->u.itl.mu) {
1434		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
1435					hba->bar0_rid, hba->bar0_res);
1436		device_printf(hba->pcidev, "alloc mem res failed\n");
1437		return -1;
1438	}
1439
1440	return 0;
1441}
1442
1443static int hptiop_alloc_pci_res_mv(struct hpt_iop_hba *hba)
1444{
1445	hba->bar0_rid = 0x10;
1446	hba->bar0_res = bus_alloc_resource_any(hba->pcidev,
1447			SYS_RES_MEMORY, &hba->bar0_rid, RF_ACTIVE);
1448
1449	if (hba->bar0_res == NULL) {
1450		device_printf(hba->pcidev, "failed to get iop bar0.\n");
1451		return -1;
1452	}
1453	hba->bar0t = rman_get_bustag(hba->bar0_res);
1454	hba->bar0h = rman_get_bushandle(hba->bar0_res);
1455	hba->u.mv.regs = (struct hpt_iopmv_regs *)
1456				rman_get_virtual(hba->bar0_res);
1457
1458	if (!hba->u.mv.regs) {
1459		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
1460					hba->bar0_rid, hba->bar0_res);
1461		device_printf(hba->pcidev, "alloc bar0 mem res failed\n");
1462		return -1;
1463	}
1464
1465	hba->bar2_rid = 0x18;
1466	hba->bar2_res = bus_alloc_resource_any(hba->pcidev,
1467			SYS_RES_MEMORY, &hba->bar2_rid, RF_ACTIVE);
1468
1469	if (hba->bar2_res == NULL) {
1470		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
1471					hba->bar0_rid, hba->bar0_res);
1472		device_printf(hba->pcidev, "failed to get iop bar2.\n");
1473		return -1;
1474	}
1475
1476	hba->bar2t = rman_get_bustag(hba->bar2_res);
1477	hba->bar2h = rman_get_bushandle(hba->bar2_res);
1478	hba->u.mv.mu = (struct hpt_iopmu_mv *)rman_get_virtual(hba->bar2_res);
1479
1480	if (!hba->u.mv.mu) {
1481		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
1482					hba->bar0_rid, hba->bar0_res);
1483		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
1484					hba->bar2_rid, hba->bar2_res);
1485		device_printf(hba->pcidev, "alloc mem bar2 res failed\n");
1486		return -1;
1487	}
1488
1489	return 0;
1490}
1491
1492static int hptiop_alloc_pci_res_mvfrey(struct hpt_iop_hba *hba)
1493{
1494	hba->bar0_rid = 0x10;
1495	hba->bar0_res = bus_alloc_resource_any(hba->pcidev,
1496			SYS_RES_MEMORY, &hba->bar0_rid, RF_ACTIVE);
1497
1498	if (hba->bar0_res == NULL) {
1499		device_printf(hba->pcidev, "failed to get iop bar0.\n");
1500		return -1;
1501	}
1502	hba->bar0t = rman_get_bustag(hba->bar0_res);
1503	hba->bar0h = rman_get_bushandle(hba->bar0_res);
1504	hba->u.mvfrey.config = (struct hpt_iop_request_get_config *)
1505				rman_get_virtual(hba->bar0_res);
1506
1507	if (!hba->u.mvfrey.config) {
1508		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
1509					hba->bar0_rid, hba->bar0_res);
1510		device_printf(hba->pcidev, "alloc bar0 mem res failed\n");
1511		return -1;
1512	}
1513
1514	hba->bar2_rid = 0x18;
1515	hba->bar2_res = bus_alloc_resource_any(hba->pcidev,
1516			SYS_RES_MEMORY, &hba->bar2_rid, RF_ACTIVE);
1517
1518	if (hba->bar2_res == NULL) {
1519		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
1520					hba->bar0_rid, hba->bar0_res);
1521		device_printf(hba->pcidev, "failed to get iop bar2.\n");
1522		return -1;
1523	}
1524
1525	hba->bar2t = rman_get_bustag(hba->bar2_res);
1526	hba->bar2h = rman_get_bushandle(hba->bar2_res);
1527	hba->u.mvfrey.mu =
1528					(struct hpt_iopmu_mvfrey *)rman_get_virtual(hba->bar2_res);
1529
1530	if (!hba->u.mvfrey.mu) {
1531		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
1532					hba->bar0_rid, hba->bar0_res);
1533		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
1534					hba->bar2_rid, hba->bar2_res);
1535		device_printf(hba->pcidev, "alloc mem bar2 res failed\n");
1536		return -1;
1537	}
1538
1539	return 0;
1540}
1541
1542static void hptiop_release_pci_res_itl(struct hpt_iop_hba *hba)
1543{
1544	if (hba->bar0_res)
1545		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
1546			hba->bar0_rid, hba->bar0_res);
1547}
1548
1549static void hptiop_release_pci_res_mv(struct hpt_iop_hba *hba)
1550{
1551	if (hba->bar0_res)
1552		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
1553			hba->bar0_rid, hba->bar0_res);
1554	if (hba->bar2_res)
1555		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
1556			hba->bar2_rid, hba->bar2_res);
1557}
1558
1559static void hptiop_release_pci_res_mvfrey(struct hpt_iop_hba *hba)
1560{
1561	if (hba->bar0_res)
1562		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
1563			hba->bar0_rid, hba->bar0_res);
1564	if (hba->bar2_res)
1565		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
1566			hba->bar2_rid, hba->bar2_res);
1567}
1568
1569static int hptiop_internal_memalloc_mv(struct hpt_iop_hba *hba)
1570{
1571	if (bus_dma_tag_create(hba->parent_dmat,
1572				1,
1573				0,
1574				BUS_SPACE_MAXADDR_32BIT,
1575				BUS_SPACE_MAXADDR,
1576				NULL, NULL,
1577				0x800 - 0x8,
1578				1,
1579				BUS_SPACE_MAXSIZE_32BIT,
1580				BUS_DMA_ALLOCNOW,
1581				NULL,
1582				NULL,
1583				&hba->ctlcfg_dmat)) {
1584		device_printf(hba->pcidev, "alloc ctlcfg_dmat failed\n");
1585		return -1;
1586	}
1587
1588	if (bus_dmamem_alloc(hba->ctlcfg_dmat, (void **)&hba->ctlcfg_ptr,
1589		BUS_DMA_WAITOK | BUS_DMA_COHERENT,
1590		&hba->ctlcfg_dmamap) != 0) {
1591			device_printf(hba->pcidev,
1592					"bus_dmamem_alloc failed!\n");
1593			bus_dma_tag_destroy(hba->ctlcfg_dmat);
1594			return -1;
1595	}
1596
1597	if (bus_dmamap_load(hba->ctlcfg_dmat,
1598			hba->ctlcfg_dmamap, hba->ctlcfg_ptr,
1599			MVIOP_IOCTLCFG_SIZE,
1600			hptiop_mv_map_ctlcfg, hba, 0)) {
1601		device_printf(hba->pcidev, "bus_dmamap_load failed!\n");
1602		if (hba->ctlcfg_dmat) {
1603			bus_dmamem_free(hba->ctlcfg_dmat,
1604				hba->ctlcfg_ptr, hba->ctlcfg_dmamap);
1605			bus_dma_tag_destroy(hba->ctlcfg_dmat);
1606		}
1607		return -1;
1608	}
1609
1610	return 0;
1611}
1612
1613static int hptiop_internal_memalloc_mvfrey(struct hpt_iop_hba *hba)
1614{
1615	u_int32_t list_count = BUS_SPACE_RD4_MVFREY2(inbound_conf_ctl);
1616
1617	list_count >>= 16;
1618
1619	if (list_count == 0) {
1620		return -1;
1621	}
1622
1623	hba->u.mvfrey.list_count = list_count;
1624	hba->u.mvfrey.internal_mem_size = 0x800
1625							+ list_count * sizeof(struct mvfrey_inlist_entry)
1626							+ list_count * sizeof(struct mvfrey_outlist_entry)
1627							+ sizeof(int);
1628	if (bus_dma_tag_create(hba->parent_dmat,
1629				1,
1630				0,
1631				BUS_SPACE_MAXADDR_32BIT,
1632				BUS_SPACE_MAXADDR,
1633				NULL, NULL,
1634				hba->u.mvfrey.internal_mem_size,
1635				1,
1636				BUS_SPACE_MAXSIZE_32BIT,
1637				BUS_DMA_ALLOCNOW,
1638				NULL,
1639				NULL,
1640				&hba->ctlcfg_dmat)) {
1641		device_printf(hba->pcidev, "alloc ctlcfg_dmat failed\n");
1642		return -1;
1643	}
1644
1645	if (bus_dmamem_alloc(hba->ctlcfg_dmat, (void **)&hba->ctlcfg_ptr,
1646		BUS_DMA_WAITOK | BUS_DMA_COHERENT,
1647		&hba->ctlcfg_dmamap) != 0) {
1648			device_printf(hba->pcidev,
1649					"bus_dmamem_alloc failed!\n");
1650			bus_dma_tag_destroy(hba->ctlcfg_dmat);
1651			return -1;
1652	}
1653
1654	if (bus_dmamap_load(hba->ctlcfg_dmat,
1655			hba->ctlcfg_dmamap, hba->ctlcfg_ptr,
1656			hba->u.mvfrey.internal_mem_size,
1657			hptiop_mvfrey_map_ctlcfg, hba, 0)) {
1658		device_printf(hba->pcidev, "bus_dmamap_load failed!\n");
1659		if (hba->ctlcfg_dmat) {
1660			bus_dmamem_free(hba->ctlcfg_dmat,
1661				hba->ctlcfg_ptr, hba->ctlcfg_dmamap);
1662			bus_dma_tag_destroy(hba->ctlcfg_dmat);
1663		}
1664		return -1;
1665	}
1666
1667	return 0;
1668}
1669
1670static int hptiop_internal_memfree_itl(struct hpt_iop_hba *hba) {
1671	return 0;
1672}
1673
1674static int hptiop_internal_memfree_mv(struct hpt_iop_hba *hba)
1675{
1676	if (hba->ctlcfg_dmat) {
1677		bus_dmamap_unload(hba->ctlcfg_dmat, hba->ctlcfg_dmamap);
1678		bus_dmamem_free(hba->ctlcfg_dmat,
1679					hba->ctlcfg_ptr, hba->ctlcfg_dmamap);
1680		bus_dma_tag_destroy(hba->ctlcfg_dmat);
1681	}
1682
1683	return 0;
1684}
1685
1686static int hptiop_internal_memfree_mvfrey(struct hpt_iop_hba *hba)
1687{
1688	if (hba->ctlcfg_dmat) {
1689		bus_dmamap_unload(hba->ctlcfg_dmat, hba->ctlcfg_dmamap);
1690		bus_dmamem_free(hba->ctlcfg_dmat,
1691					hba->ctlcfg_ptr, hba->ctlcfg_dmamap);
1692		bus_dma_tag_destroy(hba->ctlcfg_dmat);
1693	}
1694
1695	return 0;
1696}
1697
1698static int hptiop_reset_comm_mvfrey(struct hpt_iop_hba *hba)
1699{
1700	u_int32_t i = 100;
1701
1702	if (hptiop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_RESET_COMM, 3000))
1703		return -1;
1704
1705	/* wait 100ms for MCU ready */
1706	while(i--) {
1707		DELAY(1000);
1708	}
1709
1710	BUS_SPACE_WRT4_MVFREY2(inbound_base,
1711							hba->u.mvfrey.inlist_phy & 0xffffffff);
1712	BUS_SPACE_WRT4_MVFREY2(inbound_base_high,
1713							(hba->u.mvfrey.inlist_phy >> 16) >> 16);
1714
1715	BUS_SPACE_WRT4_MVFREY2(outbound_base,
1716							hba->u.mvfrey.outlist_phy & 0xffffffff);
1717	BUS_SPACE_WRT4_MVFREY2(outbound_base_high,
1718							(hba->u.mvfrey.outlist_phy >> 16) >> 16);
1719
1720	BUS_SPACE_WRT4_MVFREY2(outbound_shadow_base,
1721							hba->u.mvfrey.outlist_cptr_phy & 0xffffffff);
1722	BUS_SPACE_WRT4_MVFREY2(outbound_shadow_base_high,
1723							(hba->u.mvfrey.outlist_cptr_phy >> 16) >> 16);
1724
1725	hba->u.mvfrey.inlist_wptr = (hba->u.mvfrey.list_count - 1)
1726								| CL_POINTER_TOGGLE;
1727	*hba->u.mvfrey.outlist_cptr = (hba->u.mvfrey.list_count - 1)
1728								| CL_POINTER_TOGGLE;
1729	hba->u.mvfrey.outlist_rptr = hba->u.mvfrey.list_count - 1;
1730
1731	return 0;
1732}
1733
1734/*
1735 * CAM driver interface
1736 */
1737static device_method_t driver_methods[] = {
1738	/* Device interface */
1739	DEVMETHOD(device_probe,     hptiop_probe),
1740	DEVMETHOD(device_attach,    hptiop_attach),
1741	DEVMETHOD(device_detach,    hptiop_detach),
1742	DEVMETHOD(device_shutdown,  hptiop_shutdown),
1743	{ 0, 0 }
1744};
1745
1746static struct hptiop_adapter_ops hptiop_itl_ops = {
1747	.family	           = INTEL_BASED_IOP,
1748	.iop_wait_ready    = hptiop_wait_ready_itl,
1749	.internal_memalloc = 0,
1750	.internal_memfree  = hptiop_internal_memfree_itl,
1751	.alloc_pci_res     = hptiop_alloc_pci_res_itl,
1752	.release_pci_res   = hptiop_release_pci_res_itl,
1753	.enable_intr       = hptiop_enable_intr_itl,
1754	.disable_intr      = hptiop_disable_intr_itl,
1755	.get_config        = hptiop_get_config_itl,
1756	.set_config        = hptiop_set_config_itl,
1757	.iop_intr          = hptiop_intr_itl,
1758	.post_msg          = hptiop_post_msg_itl,
1759	.post_req          = hptiop_post_req_itl,
1760	.do_ioctl          = hptiop_do_ioctl_itl,
1761	.reset_comm        = 0,
1762};
1763
1764static struct hptiop_adapter_ops hptiop_mv_ops = {
1765	.family	           = MV_BASED_IOP,
1766	.iop_wait_ready    = hptiop_wait_ready_mv,
1767	.internal_memalloc = hptiop_internal_memalloc_mv,
1768	.internal_memfree  = hptiop_internal_memfree_mv,
1769	.alloc_pci_res     = hptiop_alloc_pci_res_mv,
1770	.release_pci_res   = hptiop_release_pci_res_mv,
1771	.enable_intr       = hptiop_enable_intr_mv,
1772	.disable_intr      = hptiop_disable_intr_mv,
1773	.get_config        = hptiop_get_config_mv,
1774	.set_config        = hptiop_set_config_mv,
1775	.iop_intr          = hptiop_intr_mv,
1776	.post_msg          = hptiop_post_msg_mv,
1777	.post_req          = hptiop_post_req_mv,
1778	.do_ioctl          = hptiop_do_ioctl_mv,
1779	.reset_comm        = 0,
1780};
1781
1782static struct hptiop_adapter_ops hptiop_mvfrey_ops = {
1783	.family	           = MVFREY_BASED_IOP,
1784	.iop_wait_ready    = hptiop_wait_ready_mvfrey,
1785	.internal_memalloc = hptiop_internal_memalloc_mvfrey,
1786	.internal_memfree  = hptiop_internal_memfree_mvfrey,
1787	.alloc_pci_res     = hptiop_alloc_pci_res_mvfrey,
1788	.release_pci_res   = hptiop_release_pci_res_mvfrey,
1789	.enable_intr       = hptiop_enable_intr_mvfrey,
1790	.disable_intr      = hptiop_disable_intr_mvfrey,
1791	.get_config        = hptiop_get_config_mvfrey,
1792	.set_config        = hptiop_set_config_mvfrey,
1793	.iop_intr          = hptiop_intr_mvfrey,
1794	.post_msg          = hptiop_post_msg_mvfrey,
1795	.post_req          = hptiop_post_req_mvfrey,
1796	.do_ioctl          = hptiop_do_ioctl_mvfrey,
1797	.reset_comm        = hptiop_reset_comm_mvfrey,
1798};
1799
1800static driver_t hptiop_pci_driver = {
1801	driver_name,
1802	driver_methods,
1803	sizeof(struct hpt_iop_hba)
1804};
1805
1806DRIVER_MODULE(hptiop, pci, hptiop_pci_driver, hptiop_devclass, 0, 0);
1807MODULE_DEPEND(hptiop, cam, 1, 1, 1);
1808
1809static int hptiop_probe(device_t dev)
1810{
1811	struct hpt_iop_hba *hba;
1812	u_int32_t id;
1813	static char buf[256];
1814	int sas = 0;
1815	struct hptiop_adapter_ops *ops;
1816
1817	if (pci_get_vendor(dev) != 0x1103)
1818		return (ENXIO);
1819
1820	id = pci_get_device(dev);
1821
1822	switch (id) {
1823		case 0x4520:
1824		case 0x4521:
1825		case 0x4522:
1826			sas = 1;
1827		case 0x3620:
1828		case 0x3622:
1829		case 0x3640:
1830			ops = &hptiop_mvfrey_ops;
1831			break;
1832		case 0x4210:
1833		case 0x4211:
1834		case 0x4310:
1835		case 0x4311:
1836		case 0x4320:
1837		case 0x4321:
1838 		case 0x4322:
1839			sas = 1;
1840		case 0x3220:
1841		case 0x3320:
1842		case 0x3410:
1843		case 0x3520:
1844		case 0x3510:
1845		case 0x3511:
1846		case 0x3521:
1847		case 0x3522:
1848		case 0x3530:
1849		case 0x3540:
1850		case 0x3560:
1851			ops = &hptiop_itl_ops;
1852			break;
1853		case 0x3020:
1854		case 0x3120:
1855		case 0x3122:
1856			ops = &hptiop_mv_ops;
1857			break;
1858		default:
1859			return (ENXIO);
1860	}
1861
1862	device_printf(dev, "adapter at PCI %d:%d:%d, IRQ %d\n",
1863		pci_get_bus(dev), pci_get_slot(dev),
1864		pci_get_function(dev), pci_get_irq(dev));
1865
1866	sprintf(buf, "RocketRAID %x %s Controller\n",
1867				id, sas ? "SAS" : "SATA");
1868	device_set_desc_copy(dev, buf);
1869
1870	hba = (struct hpt_iop_hba *)device_get_softc(dev);
1871	bzero(hba, sizeof(struct hpt_iop_hba));
1872	hba->ops = ops;
1873
1874	KdPrint(("hba->ops=%p\n", hba->ops));
1875	return 0;
1876}
1877
1878static int hptiop_attach(device_t dev)
1879{
1880	struct hpt_iop_hba *hba = (struct hpt_iop_hba *)device_get_softc(dev);
1881	struct hpt_iop_request_get_config  iop_config;
1882	struct hpt_iop_request_set_config  set_config;
1883	int rid = 0;
1884	struct cam_devq *devq;
1885	struct ccb_setasync ccb;
1886	u_int32_t unit = device_get_unit(dev);
1887
1888	device_printf(dev, "%d RocketRAID 3xxx/4xxx controller driver %s\n",
1889			unit, driver_version);
1890
1891	KdPrint(("hptiop: attach(%d, %d/%d/%d) ops=%p\n", unit,
1892		pci_get_bus(dev), pci_get_slot(dev),
1893		pci_get_function(dev), hba->ops));
1894
1895	pci_enable_busmaster(dev);
1896	hba->pcidev = dev;
1897	hba->pciunit = unit;
1898
1899	if (hba->ops->alloc_pci_res(hba))
1900		return ENXIO;
1901
1902	if (hba->ops->iop_wait_ready(hba, 2000)) {
1903		device_printf(dev, "adapter is not ready\n");
1904		goto release_pci_res;
1905	}
1906
1907	mtx_init(&hba->lock, "hptioplock", NULL, MTX_DEF);
1908
1909	if (bus_dma_tag_create(bus_get_dma_tag(dev),/* PCI parent */
1910			1,  /* alignment */
1911			0, /* boundary */
1912			BUS_SPACE_MAXADDR,  /* lowaddr */
1913			BUS_SPACE_MAXADDR,  /* highaddr */
1914			NULL, NULL,         /* filter, filterarg */
1915			BUS_SPACE_MAXSIZE_32BIT,    /* maxsize */
1916			BUS_SPACE_UNRESTRICTED, /* nsegments */
1917			BUS_SPACE_MAXSIZE_32BIT,    /* maxsegsize */
1918			0,      /* flags */
1919			NULL,   /* lockfunc */
1920			NULL,       /* lockfuncarg */
1921			&hba->parent_dmat   /* tag */))
1922	{
1923		device_printf(dev, "alloc parent_dmat failed\n");
1924		goto release_pci_res;
1925	}
1926
1927	if (hba->ops->family == MV_BASED_IOP) {
1928		if (hba->ops->internal_memalloc(hba)) {
1929			device_printf(dev, "alloc srb_dmat failed\n");
1930			goto destroy_parent_tag;
1931		}
1932	}
1933
1934	if (hba->ops->get_config(hba, &iop_config)) {
1935		device_printf(dev, "get iop config failed.\n");
1936		goto get_config_failed;
1937	}
1938
1939	hba->firmware_version = iop_config.firmware_version;
1940	hba->interface_version = iop_config.interface_version;
1941	hba->max_requests = iop_config.max_requests;
1942	hba->max_devices = iop_config.max_devices;
1943	hba->max_request_size = iop_config.request_size;
1944	hba->max_sg_count = iop_config.max_sg_count;
1945
1946	if (hba->ops->family == MVFREY_BASED_IOP) {
1947		if (hba->ops->internal_memalloc(hba)) {
1948			device_printf(dev, "alloc srb_dmat failed\n");
1949			goto destroy_parent_tag;
1950		}
1951		if (hba->ops->reset_comm(hba)) {
1952			device_printf(dev, "reset comm failed\n");
1953			goto get_config_failed;
1954		}
1955	}
1956
1957	if (bus_dma_tag_create(hba->parent_dmat,/* parent */
1958			4,  /* alignment */
1959			BUS_SPACE_MAXADDR_32BIT+1, /* boundary */
1960			BUS_SPACE_MAXADDR,  /* lowaddr */
1961			BUS_SPACE_MAXADDR,  /* highaddr */
1962			NULL, NULL,         /* filter, filterarg */
1963			PAGE_SIZE * (hba->max_sg_count-1),  /* maxsize */
1964			hba->max_sg_count,  /* nsegments */
1965			0x20000,    /* maxsegsize */
1966			BUS_DMA_ALLOCNOW,       /* flags */
1967			busdma_lock_mutex,  /* lockfunc */
1968			&hba->lock,     /* lockfuncarg */
1969			&hba->io_dmat   /* tag */))
1970	{
1971		device_printf(dev, "alloc io_dmat failed\n");
1972		goto get_config_failed;
1973	}
1974
1975	if (bus_dma_tag_create(hba->parent_dmat,/* parent */
1976			1,  /* alignment */
1977			0, /* boundary */
1978			BUS_SPACE_MAXADDR_32BIT,    /* lowaddr */
1979			BUS_SPACE_MAXADDR,  /* highaddr */
1980			NULL, NULL,         /* filter, filterarg */
1981			HPT_SRB_MAX_SIZE * HPT_SRB_MAX_QUEUE_SIZE + 0x20,
1982			1,  /* nsegments */
1983			BUS_SPACE_MAXSIZE_32BIT,    /* maxsegsize */
1984			0,      /* flags */
1985			NULL,   /* lockfunc */
1986			NULL,       /* lockfuncarg */
1987			&hba->srb_dmat  /* tag */))
1988	{
1989		device_printf(dev, "alloc srb_dmat failed\n");
1990		goto destroy_io_dmat;
1991	}
1992
1993	if (bus_dmamem_alloc(hba->srb_dmat, (void **)&hba->uncached_ptr,
1994			BUS_DMA_WAITOK | BUS_DMA_COHERENT,
1995			&hba->srb_dmamap) != 0)
1996	{
1997		device_printf(dev, "srb bus_dmamem_alloc failed!\n");
1998		goto destroy_srb_dmat;
1999	}
2000
2001	if (bus_dmamap_load(hba->srb_dmat,
2002			hba->srb_dmamap, hba->uncached_ptr,
2003			(HPT_SRB_MAX_SIZE * HPT_SRB_MAX_QUEUE_SIZE) + 0x20,
2004			hptiop_map_srb, hba, 0))
2005	{
2006		device_printf(dev, "bus_dmamap_load failed!\n");
2007		goto srb_dmamem_free;
2008	}
2009
2010	if ((devq = cam_simq_alloc(hba->max_requests - 1 )) == NULL) {
2011		device_printf(dev, "cam_simq_alloc failed\n");
2012		goto srb_dmamap_unload;
2013	}
2014
2015	hba->sim = cam_sim_alloc(hptiop_action, hptiop_poll, driver_name,
2016			hba, unit, &hba->lock, hba->max_requests - 1, 1, devq);
2017	if (!hba->sim) {
2018		device_printf(dev, "cam_sim_alloc failed\n");
2019		cam_simq_free(devq);
2020		goto srb_dmamap_unload;
2021	}
2022	hptiop_lock_adapter(hba);
2023	if (xpt_bus_register(hba->sim, dev, 0) != CAM_SUCCESS)
2024	{
2025		device_printf(dev, "xpt_bus_register failed\n");
2026		goto free_cam_sim;
2027	}
2028
2029	if (xpt_create_path(&hba->path, /*periph */ NULL,
2030			cam_sim_path(hba->sim), CAM_TARGET_WILDCARD,
2031			CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
2032		device_printf(dev, "xpt_create_path failed\n");
2033		goto deregister_xpt_bus;
2034	}
2035	hptiop_unlock_adapter(hba);
2036
2037	bzero(&set_config, sizeof(set_config));
2038	set_config.iop_id = unit;
2039	set_config.vbus_id = cam_sim_path(hba->sim);
2040	set_config.max_host_request_size = HPT_SRB_MAX_REQ_SIZE;
2041
2042	if (hba->ops->set_config(hba, &set_config)) {
2043		device_printf(dev, "set iop config failed.\n");
2044		goto free_hba_path;
2045	}
2046
2047	xpt_setup_ccb(&ccb.ccb_h, hba->path, /*priority*/5);
2048	ccb.ccb_h.func_code = XPT_SASYNC_CB;
2049	ccb.event_enable = (AC_FOUND_DEVICE | AC_LOST_DEVICE);
2050	ccb.callback = hptiop_async;
2051	ccb.callback_arg = hba->sim;
2052	xpt_action((union ccb *)&ccb);
2053
2054	rid = 0;
2055	if ((hba->irq_res = bus_alloc_resource_any(hba->pcidev, SYS_RES_IRQ,
2056			&rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
2057		device_printf(dev, "allocate irq failed!\n");
2058		goto free_hba_path;
2059	}
2060
2061	if (bus_setup_intr(hba->pcidev, hba->irq_res, INTR_TYPE_CAM | INTR_MPSAFE,
2062				NULL, hptiop_pci_intr, hba, &hba->irq_handle))
2063	{
2064		device_printf(dev, "allocate intr function failed!\n");
2065		goto free_irq_resource;
2066	}
2067
2068	if (hptiop_send_sync_msg(hba,
2069			IOPMU_INBOUND_MSG0_START_BACKGROUND_TASK, 5000)) {
2070		device_printf(dev, "fail to start background task\n");
2071		goto teartown_irq_resource;
2072	}
2073
2074	hba->ops->enable_intr(hba);
2075	hba->initialized = 1;
2076
2077	hba->ioctl_dev = make_dev(&hptiop_cdevsw, unit,
2078				UID_ROOT, GID_WHEEL /*GID_OPERATOR*/,
2079				S_IRUSR | S_IWUSR, "%s%d", driver_name, unit);
2080
2081
2082	return 0;
2083
2084
2085teartown_irq_resource:
2086	bus_teardown_intr(dev, hba->irq_res, hba->irq_handle);
2087
2088free_irq_resource:
2089	bus_release_resource(dev, SYS_RES_IRQ, 0, hba->irq_res);
2090
2091	hptiop_lock_adapter(hba);
2092free_hba_path:
2093	xpt_free_path(hba->path);
2094
2095deregister_xpt_bus:
2096	xpt_bus_deregister(cam_sim_path(hba->sim));
2097
2098free_cam_sim:
2099	cam_sim_free(hba->sim, /*free devq*/ TRUE);
2100	hptiop_unlock_adapter(hba);
2101
2102srb_dmamap_unload:
2103	if (hba->uncached_ptr)
2104		bus_dmamap_unload(hba->srb_dmat, hba->srb_dmamap);
2105
2106srb_dmamem_free:
2107	if (hba->uncached_ptr)
2108		bus_dmamem_free(hba->srb_dmat,
2109			hba->uncached_ptr, hba->srb_dmamap);
2110
2111destroy_srb_dmat:
2112	if (hba->srb_dmat)
2113		bus_dma_tag_destroy(hba->srb_dmat);
2114
2115destroy_io_dmat:
2116	if (hba->io_dmat)
2117		bus_dma_tag_destroy(hba->io_dmat);
2118
2119get_config_failed:
2120	hba->ops->internal_memfree(hba);
2121
2122destroy_parent_tag:
2123	if (hba->parent_dmat)
2124		bus_dma_tag_destroy(hba->parent_dmat);
2125
2126release_pci_res:
2127	if (hba->ops->release_pci_res)
2128		hba->ops->release_pci_res(hba);
2129
2130	return ENXIO;
2131}
2132
2133static int hptiop_detach(device_t dev)
2134{
2135	struct hpt_iop_hba * hba = (struct hpt_iop_hba *)device_get_softc(dev);
2136	int i;
2137	int error = EBUSY;
2138
2139	hptiop_lock_adapter(hba);
2140	for (i = 0; i < hba->max_devices; i++)
2141		if (hptiop_os_query_remove_device(hba, i)) {
2142			device_printf(dev, "%d file system is busy. id=%d",
2143						hba->pciunit, i);
2144			goto out;
2145		}
2146
2147	if ((error = hptiop_shutdown(dev)) != 0)
2148		goto out;
2149	if (hptiop_send_sync_msg(hba,
2150		IOPMU_INBOUND_MSG0_STOP_BACKGROUND_TASK, 60000))
2151		goto out;
2152	hptiop_unlock_adapter(hba);
2153
2154	hptiop_release_resource(hba);
2155	return (0);
2156out:
2157	hptiop_unlock_adapter(hba);
2158	return error;
2159}
2160
2161static int hptiop_shutdown(device_t dev)
2162{
2163	struct hpt_iop_hba * hba = (struct hpt_iop_hba *)device_get_softc(dev);
2164
2165	int error = 0;
2166
2167	if (hba->flag & HPT_IOCTL_FLAG_OPEN) {
2168		device_printf(dev, "%d device is busy", hba->pciunit);
2169		return EBUSY;
2170	}
2171
2172	hba->ops->disable_intr(hba);
2173
2174	if (hptiop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_SHUTDOWN, 60000))
2175		error = EBUSY;
2176
2177	return error;
2178}
2179
2180static void hptiop_pci_intr(void *arg)
2181{
2182	struct hpt_iop_hba * hba = (struct hpt_iop_hba *)arg;
2183	hptiop_lock_adapter(hba);
2184	hba->ops->iop_intr(hba);
2185	hptiop_unlock_adapter(hba);
2186}
2187
2188static void hptiop_poll(struct cam_sim *sim)
2189{
2190	struct hpt_iop_hba *hba;
2191
2192	hba = cam_sim_softc(sim);
2193	hba->ops->iop_intr(hba);
2194}
2195
2196static void hptiop_async(void * callback_arg, u_int32_t code,
2197					struct cam_path * path, void * arg)
2198{
2199}
2200
2201static void hptiop_enable_intr_itl(struct hpt_iop_hba *hba)
2202{
2203	BUS_SPACE_WRT4_ITL(outbound_intmask,
2204		~(IOPMU_OUTBOUND_INT_POSTQUEUE | IOPMU_OUTBOUND_INT_MSG0));
2205}
2206
2207static void hptiop_enable_intr_mv(struct hpt_iop_hba *hba)
2208{
2209	u_int32_t int_mask;
2210
2211	int_mask = BUS_SPACE_RD4_MV0(outbound_intmask);
2212
2213	int_mask |= MVIOP_MU_OUTBOUND_INT_POSTQUEUE
2214			| MVIOP_MU_OUTBOUND_INT_MSG;
2215    	BUS_SPACE_WRT4_MV0(outbound_intmask,int_mask);
2216}
2217
2218static void hptiop_enable_intr_mvfrey(struct hpt_iop_hba *hba)
2219{
2220	BUS_SPACE_WRT4_MVFREY2(f0_doorbell_enable, CPU_TO_F0_DRBL_MSG_A_BIT);
2221	BUS_SPACE_RD4_MVFREY2(f0_doorbell_enable);
2222
2223	BUS_SPACE_WRT4_MVFREY2(isr_enable, 0x1);
2224	BUS_SPACE_RD4_MVFREY2(isr_enable);
2225
2226	BUS_SPACE_WRT4_MVFREY2(pcie_f0_int_enable, 0x1010);
2227	BUS_SPACE_RD4_MVFREY2(pcie_f0_int_enable);
2228}
2229
2230static void hptiop_disable_intr_itl(struct hpt_iop_hba *hba)
2231{
2232	u_int32_t int_mask;
2233
2234	int_mask = BUS_SPACE_RD4_ITL(outbound_intmask);
2235
2236	int_mask |= IOPMU_OUTBOUND_INT_POSTQUEUE | IOPMU_OUTBOUND_INT_MSG0;
2237	BUS_SPACE_WRT4_ITL(outbound_intmask, int_mask);
2238	BUS_SPACE_RD4_ITL(outbound_intstatus);
2239}
2240
2241static void hptiop_disable_intr_mv(struct hpt_iop_hba *hba)
2242{
2243	u_int32_t int_mask;
2244	int_mask = BUS_SPACE_RD4_MV0(outbound_intmask);
2245
2246	int_mask &= ~(MVIOP_MU_OUTBOUND_INT_MSG
2247			| MVIOP_MU_OUTBOUND_INT_POSTQUEUE);
2248	BUS_SPACE_WRT4_MV0(outbound_intmask,int_mask);
2249	BUS_SPACE_RD4_MV0(outbound_intmask);
2250}
2251
2252static void hptiop_disable_intr_mvfrey(struct hpt_iop_hba *hba)
2253{
2254	BUS_SPACE_WRT4_MVFREY2(f0_doorbell_enable, 0);
2255	BUS_SPACE_RD4_MVFREY2(f0_doorbell_enable);
2256
2257	BUS_SPACE_WRT4_MVFREY2(isr_enable, 0);
2258	BUS_SPACE_RD4_MVFREY2(isr_enable);
2259
2260	BUS_SPACE_WRT4_MVFREY2(pcie_f0_int_enable, 0);
2261	BUS_SPACE_RD4_MVFREY2(pcie_f0_int_enable);
2262}
2263
2264static void hptiop_reset_adapter(void *argv)
2265{
2266	struct hpt_iop_hba * hba = (struct hpt_iop_hba *)argv;
2267	if (hptiop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_RESET, 60000))
2268		return;
2269	hptiop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_START_BACKGROUND_TASK, 5000);
2270}
2271
2272static void *hptiop_get_srb(struct hpt_iop_hba * hba)
2273{
2274	struct hpt_iop_srb * srb;
2275
2276	if (hba->srb_list) {
2277		srb = hba->srb_list;
2278		hba->srb_list = srb->next;
2279		return srb;
2280	}
2281
2282	return NULL;
2283}
2284
2285static void hptiop_free_srb(struct hpt_iop_hba *hba, struct hpt_iop_srb *srb)
2286{
2287	srb->next = hba->srb_list;
2288	hba->srb_list = srb;
2289}
2290
2291static void hptiop_action(struct cam_sim *sim, union ccb *ccb)
2292{
2293	struct hpt_iop_hba * hba = (struct hpt_iop_hba *)cam_sim_softc(sim);
2294	struct hpt_iop_srb * srb;
2295	int error;
2296
2297	switch (ccb->ccb_h.func_code) {
2298
2299	case XPT_SCSI_IO:
2300		if (ccb->ccb_h.target_lun != 0 ||
2301			ccb->ccb_h.target_id >= hba->max_devices ||
2302			(ccb->ccb_h.flags & CAM_CDB_PHYS))
2303		{
2304			ccb->ccb_h.status = CAM_TID_INVALID;
2305			xpt_done(ccb);
2306			return;
2307		}
2308
2309		if ((srb = hptiop_get_srb(hba)) == NULL) {
2310			device_printf(hba->pcidev, "srb allocated failed");
2311			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2312			xpt_done(ccb);
2313			return;
2314		}
2315
2316		srb->ccb = ccb;
2317		error = bus_dmamap_load_ccb(hba->io_dmat,
2318					    srb->dma_map,
2319					    ccb,
2320					    hptiop_post_scsi_command,
2321					    srb,
2322					    0);
2323
2324		if (error && error != EINPROGRESS) {
2325			device_printf(hba->pcidev,
2326				"%d bus_dmamap_load error %d",
2327				hba->pciunit, error);
2328			xpt_freeze_simq(hba->sim, 1);
2329			ccb->ccb_h.status = CAM_REQ_CMP_ERR;
2330			hptiop_free_srb(hba, srb);
2331			xpt_done(ccb);
2332			return;
2333		}
2334
2335		return;
2336
2337	case XPT_RESET_BUS:
2338		device_printf(hba->pcidev, "reset adapter");
2339		hba->msg_done = 0;
2340		hptiop_reset_adapter(hba);
2341		break;
2342
2343	case XPT_GET_TRAN_SETTINGS:
2344	case XPT_SET_TRAN_SETTINGS:
2345		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
2346		break;
2347
2348	case XPT_CALC_GEOMETRY:
2349		cam_calc_geometry(&ccb->ccg, 1);
2350		break;
2351
2352	case XPT_PATH_INQ:
2353	{
2354		struct ccb_pathinq *cpi = &ccb->cpi;
2355
2356		cpi->version_num = 1;
2357		cpi->hba_inquiry = PI_SDTR_ABLE;
2358		cpi->target_sprt = 0;
2359		cpi->hba_misc = PIM_NOBUSRESET;
2360		cpi->hba_eng_cnt = 0;
2361		cpi->max_target = hba->max_devices;
2362		cpi->max_lun = 0;
2363		cpi->unit_number = cam_sim_unit(sim);
2364		cpi->bus_id = cam_sim_bus(sim);
2365		cpi->initiator_id = hba->max_devices;
2366		cpi->base_transfer_speed = 3300;
2367
2368		strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
2369		strlcpy(cpi->hba_vid, "HPT   ", HBA_IDLEN);
2370		strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
2371		cpi->transport = XPORT_SPI;
2372		cpi->transport_version = 2;
2373		cpi->protocol = PROTO_SCSI;
2374		cpi->protocol_version = SCSI_REV_2;
2375		cpi->ccb_h.status = CAM_REQ_CMP;
2376		break;
2377	}
2378
2379	default:
2380		ccb->ccb_h.status = CAM_REQ_INVALID;
2381		break;
2382	}
2383
2384	xpt_done(ccb);
2385	return;
2386}
2387
2388static void hptiop_post_req_itl(struct hpt_iop_hba *hba,
2389				struct hpt_iop_srb *srb,
2390				bus_dma_segment_t *segs, int nsegs)
2391{
2392	int idx;
2393	union ccb *ccb = srb->ccb;
2394	u_int8_t *cdb;
2395
2396	if (ccb->ccb_h.flags & CAM_CDB_POINTER)
2397		cdb = ccb->csio.cdb_io.cdb_ptr;
2398	else
2399		cdb = ccb->csio.cdb_io.cdb_bytes;
2400
2401	KdPrint(("ccb=%p %x-%x-%x\n",
2402		ccb, *(u_int32_t *)cdb, *((u_int32_t *)cdb+1), *((u_int32_t *)cdb+2)));
2403
2404	if (srb->srb_flag & HPT_SRB_FLAG_HIGH_MEM_ACESS) {
2405		u_int32_t iop_req32;
2406		struct hpt_iop_request_scsi_command req;
2407
2408		iop_req32 = BUS_SPACE_RD4_ITL(inbound_queue);
2409
2410		if (iop_req32 == IOPMU_QUEUE_EMPTY) {
2411			device_printf(hba->pcidev, "invalid req offset\n");
2412			ccb->ccb_h.status = CAM_BUSY;
2413			bus_dmamap_unload(hba->io_dmat, srb->dma_map);
2414			hptiop_free_srb(hba, srb);
2415			xpt_done(ccb);
2416			return;
2417		}
2418
2419		if (ccb->csio.dxfer_len && nsegs > 0) {
2420			struct hpt_iopsg *psg = req.sg_list;
2421			for (idx = 0; idx < nsegs; idx++, psg++) {
2422				psg->pci_address = (u_int64_t)segs[idx].ds_addr;
2423				psg->size = segs[idx].ds_len;
2424				psg->eot = 0;
2425			}
2426			psg[-1].eot = 1;
2427		}
2428
2429		bcopy(cdb, req.cdb, ccb->csio.cdb_len);
2430
2431		req.header.size =
2432				offsetof(struct hpt_iop_request_scsi_command, sg_list)
2433				+ nsegs*sizeof(struct hpt_iopsg);
2434		req.header.type = IOP_REQUEST_TYPE_SCSI_COMMAND;
2435		req.header.flags = 0;
2436		req.header.result = IOP_RESULT_PENDING;
2437		req.header.context = (u_int64_t)(unsigned long)srb;
2438		req.dataxfer_length = ccb->csio.dxfer_len;
2439		req.channel =  0;
2440		req.target =  ccb->ccb_h.target_id;
2441		req.lun =  ccb->ccb_h.target_lun;
2442
2443		bus_space_write_region_1(hba->bar0t, hba->bar0h, iop_req32,
2444			(u_int8_t *)&req, req.header.size);
2445
2446		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
2447			bus_dmamap_sync(hba->io_dmat,
2448				srb->dma_map, BUS_DMASYNC_PREREAD);
2449		}
2450		else if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
2451			bus_dmamap_sync(hba->io_dmat,
2452				srb->dma_map, BUS_DMASYNC_PREWRITE);
2453
2454		BUS_SPACE_WRT4_ITL(inbound_queue,iop_req32);
2455	} else {
2456		struct hpt_iop_request_scsi_command *req;
2457
2458		req = (struct hpt_iop_request_scsi_command *)srb;
2459		if (ccb->csio.dxfer_len && nsegs > 0) {
2460			struct hpt_iopsg *psg = req->sg_list;
2461			for (idx = 0; idx < nsegs; idx++, psg++) {
2462				psg->pci_address =
2463					(u_int64_t)segs[idx].ds_addr;
2464				psg->size = segs[idx].ds_len;
2465				psg->eot = 0;
2466			}
2467			psg[-1].eot = 1;
2468		}
2469
2470		bcopy(cdb, req->cdb, ccb->csio.cdb_len);
2471
2472		req->header.type = IOP_REQUEST_TYPE_SCSI_COMMAND;
2473		req->header.result = IOP_RESULT_PENDING;
2474		req->dataxfer_length = ccb->csio.dxfer_len;
2475		req->channel =  0;
2476		req->target =  ccb->ccb_h.target_id;
2477		req->lun =  ccb->ccb_h.target_lun;
2478		req->header.size =
2479			offsetof(struct hpt_iop_request_scsi_command, sg_list)
2480			+ nsegs*sizeof(struct hpt_iopsg);
2481		req->header.context = (u_int64_t)srb->index |
2482						IOPMU_QUEUE_ADDR_HOST_BIT;
2483		req->header.flags = IOP_REQUEST_FLAG_OUTPUT_CONTEXT;
2484
2485		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
2486			bus_dmamap_sync(hba->io_dmat,
2487				srb->dma_map, BUS_DMASYNC_PREREAD);
2488		}else if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) {
2489			bus_dmamap_sync(hba->io_dmat,
2490				srb->dma_map, BUS_DMASYNC_PREWRITE);
2491		}
2492
2493		if (hba->firmware_version > 0x01020000
2494			|| hba->interface_version > 0x01020000) {
2495			u_int32_t size_bits;
2496
2497			if (req->header.size < 256)
2498				size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT;
2499			else if (req->header.size < 512)
2500				size_bits = IOPMU_QUEUE_ADDR_HOST_BIT;
2501			else
2502				size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT
2503						| IOPMU_QUEUE_ADDR_HOST_BIT;
2504
2505			BUS_SPACE_WRT4_ITL(inbound_queue,
2506				(u_int32_t)srb->phy_addr | size_bits);
2507		} else
2508			BUS_SPACE_WRT4_ITL(inbound_queue, (u_int32_t)srb->phy_addr
2509				|IOPMU_QUEUE_ADDR_HOST_BIT);
2510	}
2511}
2512
2513static void hptiop_post_req_mv(struct hpt_iop_hba *hba,
2514				struct hpt_iop_srb *srb,
2515				bus_dma_segment_t *segs, int nsegs)
2516{
2517	int idx, size;
2518	union ccb *ccb = srb->ccb;
2519	u_int8_t *cdb;
2520	struct hpt_iop_request_scsi_command *req;
2521	u_int64_t req_phy;
2522
2523    	req = (struct hpt_iop_request_scsi_command *)srb;
2524	req_phy = srb->phy_addr;
2525
2526	if (ccb->csio.dxfer_len && nsegs > 0) {
2527		struct hpt_iopsg *psg = req->sg_list;
2528		for (idx = 0; idx < nsegs; idx++, psg++) {
2529			psg->pci_address = (u_int64_t)segs[idx].ds_addr;
2530			psg->size = segs[idx].ds_len;
2531			psg->eot = 0;
2532		}
2533		psg[-1].eot = 1;
2534	}
2535	if (ccb->ccb_h.flags & CAM_CDB_POINTER)
2536		cdb = ccb->csio.cdb_io.cdb_ptr;
2537	else
2538		cdb = ccb->csio.cdb_io.cdb_bytes;
2539
2540	bcopy(cdb, req->cdb, ccb->csio.cdb_len);
2541	req->header.type = IOP_REQUEST_TYPE_SCSI_COMMAND;
2542	req->header.result = IOP_RESULT_PENDING;
2543	req->dataxfer_length = ccb->csio.dxfer_len;
2544	req->channel = 0;
2545	req->target =  ccb->ccb_h.target_id;
2546	req->lun =  ccb->ccb_h.target_lun;
2547	req->header.size = sizeof(struct hpt_iop_request_scsi_command)
2548				- sizeof(struct hpt_iopsg)
2549				+ nsegs * sizeof(struct hpt_iopsg);
2550	if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
2551		bus_dmamap_sync(hba->io_dmat,
2552			srb->dma_map, BUS_DMASYNC_PREREAD);
2553	}
2554	else if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
2555		bus_dmamap_sync(hba->io_dmat,
2556			srb->dma_map, BUS_DMASYNC_PREWRITE);
2557	req->header.context = (u_int64_t)srb->index
2558					<< MVIOP_REQUEST_NUMBER_START_BIT
2559					| MVIOP_CMD_TYPE_SCSI;
2560	req->header.flags = IOP_REQUEST_FLAG_OUTPUT_CONTEXT;
2561	size = req->header.size >> 8;
2562	hptiop_mv_inbound_write(req_phy
2563			| MVIOP_MU_QUEUE_ADDR_HOST_BIT
2564			| imin(3, size), hba);
2565}
2566
2567static void hptiop_post_req_mvfrey(struct hpt_iop_hba *hba,
2568				struct hpt_iop_srb *srb,
2569				bus_dma_segment_t *segs, int nsegs)
2570{
2571	int idx, index;
2572	union ccb *ccb = srb->ccb;
2573	u_int8_t *cdb;
2574	struct hpt_iop_request_scsi_command *req;
2575	u_int64_t req_phy;
2576
2577	req = (struct hpt_iop_request_scsi_command *)srb;
2578	req_phy = srb->phy_addr;
2579
2580	if (ccb->csio.dxfer_len && nsegs > 0) {
2581		struct hpt_iopsg *psg = req->sg_list;
2582		for (idx = 0; idx < nsegs; idx++, psg++) {
2583			psg->pci_address = (u_int64_t)segs[idx].ds_addr | 1;
2584			psg->size = segs[idx].ds_len;
2585			psg->eot = 0;
2586		}
2587		psg[-1].eot = 1;
2588	}
2589	if (ccb->ccb_h.flags & CAM_CDB_POINTER)
2590		cdb = ccb->csio.cdb_io.cdb_ptr;
2591	else
2592		cdb = ccb->csio.cdb_io.cdb_bytes;
2593
2594	bcopy(cdb, req->cdb, ccb->csio.cdb_len);
2595	req->header.type = IOP_REQUEST_TYPE_SCSI_COMMAND;
2596	req->header.result = IOP_RESULT_PENDING;
2597	req->dataxfer_length = ccb->csio.dxfer_len;
2598	req->channel = 0;
2599	req->target = ccb->ccb_h.target_id;
2600	req->lun = ccb->ccb_h.target_lun;
2601	req->header.size = sizeof(struct hpt_iop_request_scsi_command)
2602				- sizeof(struct hpt_iopsg)
2603				+ nsegs * sizeof(struct hpt_iopsg);
2604	if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
2605		bus_dmamap_sync(hba->io_dmat,
2606			srb->dma_map, BUS_DMASYNC_PREREAD);
2607	}
2608	else if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
2609		bus_dmamap_sync(hba->io_dmat,
2610			srb->dma_map, BUS_DMASYNC_PREWRITE);
2611
2612	req->header.flags = IOP_REQUEST_FLAG_OUTPUT_CONTEXT
2613						| IOP_REQUEST_FLAG_ADDR_BITS
2614						| ((req_phy >> 16) & 0xffff0000);
2615	req->header.context = ((req_phy & 0xffffffff) << 32 )
2616						| srb->index << 4
2617						| IOPMU_QUEUE_ADDR_HOST_BIT | req->header.type;
2618
2619	hba->u.mvfrey.inlist_wptr++;
2620	index = hba->u.mvfrey.inlist_wptr & 0x3fff;
2621
2622	if (index == hba->u.mvfrey.list_count) {
2623		index = 0;
2624		hba->u.mvfrey.inlist_wptr &= ~0x3fff;
2625		hba->u.mvfrey.inlist_wptr ^= CL_POINTER_TOGGLE;
2626	}
2627
2628	hba->u.mvfrey.inlist[index].addr = req_phy;
2629	hba->u.mvfrey.inlist[index].intrfc_len = (req->header.size + 3) / 4;
2630
2631	BUS_SPACE_WRT4_MVFREY2(inbound_write_ptr, hba->u.mvfrey.inlist_wptr);
2632	BUS_SPACE_RD4_MVFREY2(inbound_write_ptr);
2633
2634	if (req->header.type == IOP_REQUEST_TYPE_SCSI_COMMAND) {
2635		callout_reset(&srb->timeout, 20 * hz, hptiop_reset_adapter, hba);
2636	}
2637}
2638
2639static void hptiop_post_scsi_command(void *arg, bus_dma_segment_t *segs,
2640					int nsegs, int error)
2641{
2642	struct hpt_iop_srb *srb = (struct hpt_iop_srb *)arg;
2643	union ccb *ccb = srb->ccb;
2644	struct hpt_iop_hba *hba = srb->hba;
2645
2646	if (error || nsegs > hba->max_sg_count) {
2647		KdPrint(("hptiop: func_code=%x tid=%x lun=%jx nsegs=%d\n",
2648			ccb->ccb_h.func_code,
2649			ccb->ccb_h.target_id,
2650			(uintmax_t)ccb->ccb_h.target_lun, nsegs));
2651		ccb->ccb_h.status = CAM_BUSY;
2652		bus_dmamap_unload(hba->io_dmat, srb->dma_map);
2653		hptiop_free_srb(hba, srb);
2654		xpt_done(ccb);
2655		return;
2656	}
2657
2658	hba->ops->post_req(hba, srb, segs, nsegs);
2659}
2660
2661static void hptiop_mv_map_ctlcfg(void *arg, bus_dma_segment_t *segs,
2662				int nsegs, int error)
2663{
2664	struct hpt_iop_hba *hba = (struct hpt_iop_hba *)arg;
2665	hba->ctlcfgcmd_phy = ((u_int64_t)segs->ds_addr + 0x1F)
2666				& ~(u_int64_t)0x1F;
2667	hba->ctlcfg_ptr = (u_int8_t *)(((unsigned long)hba->ctlcfg_ptr + 0x1F)
2668				& ~0x1F);
2669}
2670
2671static void hptiop_mvfrey_map_ctlcfg(void *arg, bus_dma_segment_t *segs,
2672				int nsegs, int error)
2673{
2674	struct hpt_iop_hba *hba = (struct hpt_iop_hba *)arg;
2675	char *p;
2676	u_int64_t phy;
2677	u_int32_t list_count = hba->u.mvfrey.list_count;
2678
2679	phy = ((u_int64_t)segs->ds_addr + 0x1F)
2680				& ~(u_int64_t)0x1F;
2681	p = (u_int8_t *)(((unsigned long)hba->ctlcfg_ptr + 0x1F)
2682				& ~0x1F);
2683
2684	hba->ctlcfgcmd_phy = phy;
2685	hba->ctlcfg_ptr = p;
2686
2687	p += 0x800;
2688	phy += 0x800;
2689
2690	hba->u.mvfrey.inlist = (struct mvfrey_inlist_entry *)p;
2691	hba->u.mvfrey.inlist_phy = phy;
2692
2693	p += list_count * sizeof(struct mvfrey_inlist_entry);
2694	phy += list_count * sizeof(struct mvfrey_inlist_entry);
2695
2696	hba->u.mvfrey.outlist = (struct mvfrey_outlist_entry *)p;
2697	hba->u.mvfrey.outlist_phy = phy;
2698
2699	p += list_count * sizeof(struct mvfrey_outlist_entry);
2700	phy += list_count * sizeof(struct mvfrey_outlist_entry);
2701
2702	hba->u.mvfrey.outlist_cptr = (u_int32_t *)p;
2703	hba->u.mvfrey.outlist_cptr_phy = phy;
2704}
2705
2706static void hptiop_map_srb(void *arg, bus_dma_segment_t *segs,
2707				int nsegs, int error)
2708{
2709	struct hpt_iop_hba * hba = (struct hpt_iop_hba *)arg;
2710	bus_addr_t phy_addr = (segs->ds_addr + 0x1F) & ~(bus_addr_t)0x1F;
2711	struct hpt_iop_srb *srb, *tmp_srb;
2712	int i;
2713
2714	if (error || nsegs == 0) {
2715		device_printf(hba->pcidev, "hptiop_map_srb error");
2716		return;
2717	}
2718
2719	/* map srb */
2720	srb = (struct hpt_iop_srb *)
2721		(((unsigned long)hba->uncached_ptr + 0x1F)
2722		& ~(unsigned long)0x1F);
2723
2724	for (i = 0; i < HPT_SRB_MAX_QUEUE_SIZE; i++) {
2725		tmp_srb = (struct hpt_iop_srb *)
2726					((char *)srb + i * HPT_SRB_MAX_SIZE);
2727		if (((unsigned long)tmp_srb & 0x1F) == 0) {
2728			if (bus_dmamap_create(hba->io_dmat,
2729						0, &tmp_srb->dma_map)) {
2730				device_printf(hba->pcidev, "dmamap create failed");
2731				return;
2732			}
2733
2734			bzero(tmp_srb, sizeof(struct hpt_iop_srb));
2735			tmp_srb->hba = hba;
2736			tmp_srb->index = i;
2737			if (hba->ctlcfg_ptr == 0) {/*itl iop*/
2738				tmp_srb->phy_addr = (u_int64_t)(u_int32_t)
2739							(phy_addr >> 5);
2740				if (phy_addr & IOPMU_MAX_MEM_SUPPORT_MASK_32G)
2741					tmp_srb->srb_flag =
2742						HPT_SRB_FLAG_HIGH_MEM_ACESS;
2743			} else {
2744				tmp_srb->phy_addr = phy_addr;
2745			}
2746
2747			callout_init_mtx(&tmp_srb->timeout, &hba->lock, 0);
2748			hptiop_free_srb(hba, tmp_srb);
2749			hba->srb[i] = tmp_srb;
2750			phy_addr += HPT_SRB_MAX_SIZE;
2751		}
2752		else {
2753			device_printf(hba->pcidev, "invalid alignment");
2754			return;
2755		}
2756	}
2757}
2758
2759static void hptiop_os_message_callback(struct hpt_iop_hba * hba, u_int32_t msg)
2760{
2761	hba->msg_done = 1;
2762}
2763
2764static  int hptiop_os_query_remove_device(struct hpt_iop_hba * hba,
2765						int target_id)
2766{
2767	struct cam_periph       *periph = NULL;
2768	struct cam_path         *path;
2769	int                     status, retval = 0;
2770
2771	status = xpt_create_path(&path, NULL, hba->sim->path_id, target_id, 0);
2772
2773	if (status == CAM_REQ_CMP) {
2774		if ((periph = cam_periph_find(path, "da")) != NULL) {
2775			if (periph->refcount >= 1) {
2776				device_printf(hba->pcidev, "%d ,"
2777					"target_id=0x%x,"
2778					"refcount=%d",
2779				    hba->pciunit, target_id, periph->refcount);
2780				retval = -1;
2781			}
2782		}
2783		xpt_free_path(path);
2784	}
2785	return retval;
2786}
2787
2788static void hptiop_release_resource(struct hpt_iop_hba *hba)
2789{
2790	int i;
2791
2792	if (hba->ioctl_dev)
2793		destroy_dev(hba->ioctl_dev);
2794
2795	if (hba->path) {
2796		struct ccb_setasync ccb;
2797
2798		xpt_setup_ccb(&ccb.ccb_h, hba->path, /*priority*/5);
2799		ccb.ccb_h.func_code = XPT_SASYNC_CB;
2800		ccb.event_enable = 0;
2801		ccb.callback = hptiop_async;
2802		ccb.callback_arg = hba->sim;
2803		xpt_action((union ccb *)&ccb);
2804		xpt_free_path(hba->path);
2805	}
2806
2807	if (hba->irq_handle)
2808		bus_teardown_intr(hba->pcidev, hba->irq_res, hba->irq_handle);
2809
2810	if (hba->sim) {
2811		hptiop_lock_adapter(hba);
2812		xpt_bus_deregister(cam_sim_path(hba->sim));
2813		cam_sim_free(hba->sim, TRUE);
2814		hptiop_unlock_adapter(hba);
2815	}
2816
2817	if (hba->ctlcfg_dmat) {
2818		bus_dmamap_unload(hba->ctlcfg_dmat, hba->ctlcfg_dmamap);
2819		bus_dmamem_free(hba->ctlcfg_dmat,
2820					hba->ctlcfg_ptr, hba->ctlcfg_dmamap);
2821		bus_dma_tag_destroy(hba->ctlcfg_dmat);
2822	}
2823
2824	for (i = 0; i < HPT_SRB_MAX_QUEUE_SIZE; i++) {
2825		struct hpt_iop_srb *srb = hba->srb[i];
2826		if (srb->dma_map)
2827			bus_dmamap_destroy(hba->io_dmat, srb->dma_map);
2828		callout_drain(&srb->timeout);
2829	}
2830
2831	if (hba->srb_dmat) {
2832		bus_dmamap_unload(hba->srb_dmat, hba->srb_dmamap);
2833		bus_dmamap_destroy(hba->srb_dmat, hba->srb_dmamap);
2834		bus_dma_tag_destroy(hba->srb_dmat);
2835	}
2836
2837	if (hba->io_dmat)
2838		bus_dma_tag_destroy(hba->io_dmat);
2839
2840	if (hba->parent_dmat)
2841		bus_dma_tag_destroy(hba->parent_dmat);
2842
2843	if (hba->irq_res)
2844		bus_release_resource(hba->pcidev, SYS_RES_IRQ,
2845					0, hba->irq_res);
2846
2847	if (hba->bar0_res)
2848		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
2849					hba->bar0_rid, hba->bar0_res);
2850	if (hba->bar2_res)
2851		bus_release_resource(hba->pcidev, SYS_RES_MEMORY,
2852					hba->bar2_rid, hba->bar2_res);
2853	mtx_destroy(&hba->lock);
2854}
2855