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