advansys.c revision 115343
1165138Syongari/*
2165138Syongari * Generic driver for the Advanced Systems Inc. SCSI controllers
3165138Syongari * Product specific probe and attach routines can be found in:
4165138Syongari *
5165138Syongari * i386/isa/adv_isa.c	ABP5140, ABP542, ABP5150, ABP842, ABP852
6165138Syongari * i386/eisa/adv_eisa.c	ABP742, ABP752
7165138Syongari * pci/adv_pci.c	ABP920, ABP930, ABP930U, ABP930UA, ABP940, ABP940U,
8165138Syongari *			ABP940UA, ABP950, ABP960, ABP960U, ABP960UA,
9165138Syongari *			ABP970, ABP970U
10165138Syongari *
11165138Syongari * Copyright (c) 1996-2000 Justin Gibbs.
12165138Syongari * All rights reserved.
13165138Syongari *
14165138Syongari * Redistribution and use in source and binary forms, with or without
15165138Syongari * modification, are permitted provided that the following conditions
16165138Syongari * are met:
17165138Syongari * 1. Redistributions of source code must retain the above copyright
18165138Syongari *    notice, this list of conditions, and the following disclaimer,
19165138Syongari *    without modification, immediately at the beginning of the file.
20165138Syongari * 2. The name of the author may not be used to endorse or promote products
21165138Syongari *    derived from this software without specific prior written permission.
22165138Syongari *
23165138Syongari * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24165138Syongari * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25165138Syongari * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26165138Syongari * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
27165138Syongari * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28165138Syongari * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29165138Syongari * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30165138Syongari * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31165138Syongari * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32165138Syongari * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33165138Syongari * SUCH DAMAGE.
34165138Syongari *
35165138Syongari * $FreeBSD: head/sys/dev/advansys/advansys.c 115343 2003-05-27 04:59:59Z scottl $
36165138Syongari */
37165138Syongari/*
38165138Syongari * Ported from:
39165138Syongari * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
40165138Syongari *
41165138Syongari * Copyright (c) 1995-1997 Advanced System Products, Inc.
42165138Syongari * All Rights Reserved.
43165138Syongari *
44165138Syongari * Redistribution and use in source and binary forms, with or without
45165138Syongari * modification, are permitted provided that redistributions of source
46165138Syongari * code retain the above copyright notice and this comment without
47165138Syongari * modification.
48165138Syongari */
49165138Syongari
50165138Syongari#include <sys/param.h>
51165138Syongari#include <sys/systm.h>
52165138Syongari#include <sys/malloc.h>
53165138Syongari#include <sys/kernel.h>
54165138Syongari
55165138Syongari#include <machine/bus_pio.h>
56165138Syongari#include <machine/bus.h>
57165138Syongari#include <machine/resource.h>
58165138Syongari#include <sys/bus.h>
59165138Syongari#include <sys/rman.h>
60165138Syongari
61165138Syongari#include <cam/cam.h>
62165138Syongari#include <cam/cam_ccb.h>
63165138Syongari#include <cam/cam_sim.h>
64165138Syongari#include <cam/cam_xpt_sim.h>
65165138Syongari#include <cam/cam_xpt_periph.h>
66165138Syongari#include <cam/cam_debug.h>
67165138Syongari
68165138Syongari#include <cam/scsi/scsi_all.h>
69165138Syongari#include <cam/scsi/scsi_message.h>
70165138Syongari
71165138Syongari#include <vm/vm.h>
72165138Syongari#include <vm/vm_param.h>
73165138Syongari#include <vm/pmap.h>
74165138Syongari
75165138Syongari#include <dev/advansys/advansys.h>
76165138Syongari
77165138Syongaristatic void	adv_action(struct cam_sim *sim, union ccb *ccb);
78165138Syongaristatic void	adv_execute_ccb(void *arg, bus_dma_segment_t *dm_segs,
79165138Syongari				int nsegments, int error);
80165138Syongaristatic void	adv_poll(struct cam_sim *sim);
81165138Syongaristatic void	adv_run_doneq(struct adv_softc *adv);
82165138Syongaristatic struct adv_ccb_info *
83165138Syongari		adv_alloc_ccb_info(struct adv_softc *adv);
84165138Syongaristatic void	adv_destroy_ccb_info(struct adv_softc *adv,
85165138Syongari				     struct adv_ccb_info *cinfo);
86165138Syongaristatic __inline struct adv_ccb_info *
87165138Syongari		adv_get_ccb_info(struct adv_softc *adv);
88165138Syongaristatic __inline void adv_free_ccb_info(struct adv_softc *adv,
89165138Syongari				       struct adv_ccb_info *cinfo);
90165138Syongaristatic __inline void adv_set_state(struct adv_softc *adv, adv_state state);
91165138Syongaristatic __inline void adv_clear_state(struct adv_softc *adv, union ccb* ccb);
92165138Syongaristatic void adv_clear_state_really(struct adv_softc *adv, union ccb* ccb);
93165138Syongari
94165138Syongaristatic __inline struct adv_ccb_info *
95165138Syongariadv_get_ccb_info(struct adv_softc *adv)
96165138Syongari{
97165138Syongari	struct adv_ccb_info *cinfo;
98165138Syongari	int opri;
99165138Syongari
100165138Syongari	opri = splcam();
101165138Syongari	if ((cinfo = SLIST_FIRST(&adv->free_ccb_infos)) != NULL) {
102165138Syongari		SLIST_REMOVE_HEAD(&adv->free_ccb_infos, links);
103165138Syongari	} else {
104165138Syongari		cinfo = adv_alloc_ccb_info(adv);
105165138Syongari	}
106165138Syongari	splx(opri);
107165138Syongari
108165138Syongari	return (cinfo);
109165138Syongari}
110165138Syongari
111165138Syongaristatic __inline void
112165138Syongariadv_free_ccb_info(struct adv_softc *adv, struct adv_ccb_info *cinfo)
113165138Syongari{
114165138Syongari	int opri;
115165138Syongari
116165138Syongari	opri = splcam();
117165138Syongari	cinfo->state = ACCB_FREE;
118165138Syongari	SLIST_INSERT_HEAD(&adv->free_ccb_infos, cinfo, links);
119165138Syongari	splx(opri);
120165138Syongari}
121165138Syongari
122165138Syongaristatic __inline void
123165138Syongariadv_set_state(struct adv_softc *adv, adv_state state)
124165138Syongari{
125165138Syongari	if (adv->state == 0)
126165138Syongari		xpt_freeze_simq(adv->sim, /*count*/1);
127165138Syongari	adv->state |= state;
128165138Syongari}
129165138Syongari
130165138Syongaristatic __inline void
131165138Syongariadv_clear_state(struct adv_softc *adv, union ccb* ccb)
132165138Syongari{
133165138Syongari	if (adv->state != 0)
134165138Syongari		adv_clear_state_really(adv, ccb);
135165138Syongari}
136165138Syongari
137165138Syongaristatic void
138165138Syongariadv_clear_state_really(struct adv_softc *adv, union ccb* ccb)
139165138Syongari{
140165138Syongari	if ((adv->state & ADV_BUSDMA_BLOCK_CLEARED) != 0)
141165138Syongari		adv->state &= ~(ADV_BUSDMA_BLOCK_CLEARED|ADV_BUSDMA_BLOCK);
142165138Syongari	if ((adv->state & ADV_RESOURCE_SHORTAGE) != 0) {
143165138Syongari		int openings;
144165138Syongari
145165138Syongari		openings = adv->max_openings - adv->cur_active - ADV_MIN_FREE_Q;
146165138Syongari		if (openings >= adv->openings_needed) {
147165138Syongari			adv->state &= ~ADV_RESOURCE_SHORTAGE;
148165138Syongari			adv->openings_needed = 0;
149165138Syongari		}
150165138Syongari	}
151165138Syongari
152165138Syongari	if ((adv->state & ADV_IN_TIMEOUT) != 0) {
153165138Syongari		struct adv_ccb_info *cinfo;
154165138Syongari
155165138Syongari		cinfo = (struct adv_ccb_info *)ccb->ccb_h.ccb_cinfo_ptr;
156165138Syongari		if ((cinfo->state & ACCB_RECOVERY_CCB) != 0) {
157165138Syongari			struct ccb_hdr *ccb_h;
158165138Syongari
159165138Syongari			/*
160165138Syongari			 * We now traverse our list of pending CCBs
161165138Syongari			 * and reinstate their timeouts.
162165138Syongari			 */
163165138Syongari			ccb_h = LIST_FIRST(&adv->pending_ccbs);
164165138Syongari			while (ccb_h != NULL) {
165165138Syongari				ccb_h->timeout_ch =
166165138Syongari				    timeout(adv_timeout, (caddr_t)ccb_h,
167165138Syongari					    (ccb_h->timeout * hz) / 1000);
168165138Syongari				ccb_h = LIST_NEXT(ccb_h, sim_links.le);
169165138Syongari			}
170165138Syongari			adv->state &= ~ADV_IN_TIMEOUT;
171165138Syongari			printf("%s: No longer in timeout\n", adv_name(adv));
172165138Syongari		}
173165138Syongari	}
174165138Syongari	if (adv->state == 0)
175165138Syongari		ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
176165138Syongari}
177165138Syongari
178165138Syongarivoid
179165138Syongariadv_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
180165138Syongari{
181165138Syongari	bus_addr_t* physaddr;
182165138Syongari
183165138Syongari	physaddr = (bus_addr_t*)arg;
184165138Syongari	*physaddr = segs->ds_addr;
185165138Syongari}
186165138Syongari
187165138Syongarichar *
188165138Syongariadv_name(struct adv_softc *adv)
189165138Syongari{
190165138Syongari	static char name[10];
191165138Syongari
192165138Syongari	snprintf(name, sizeof(name), "adv%d", adv->unit);
193165138Syongari	return (name);
194165138Syongari}
195165138Syongari
196165138Syongaristatic void
197165138Syongariadv_action(struct cam_sim *sim, union ccb *ccb)
198165138Syongari{
199165138Syongari	struct adv_softc *adv;
200165138Syongari
201165138Syongari	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("adv_action\n"));
202165138Syongari
203165138Syongari	adv = (struct adv_softc *)cam_sim_softc(sim);
204165138Syongari
205165138Syongari	switch (ccb->ccb_h.func_code) {
206165138Syongari	/* Common cases first */
207165138Syongari	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
208165138Syongari	{
209165138Syongari		struct	ccb_hdr *ccb_h;
210165138Syongari		struct	ccb_scsiio *csio;
211165138Syongari		struct	adv_ccb_info *cinfo;
212165138Syongari
213165138Syongari		ccb_h = &ccb->ccb_h;
214165138Syongari		csio = &ccb->csio;
215165138Syongari		cinfo = adv_get_ccb_info(adv);
216165138Syongari		if (cinfo == NULL)
217165138Syongari			panic("XXX Handle CCB info error!!!");
218165138Syongari
219165138Syongari		ccb_h->ccb_cinfo_ptr = cinfo;
220165138Syongari		cinfo->ccb = ccb;
221165138Syongari
222165138Syongari		/* Only use S/G if there is a transfer */
223165138Syongari		if ((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
224165138Syongari			if ((ccb_h->flags & CAM_SCATTER_VALID) == 0) {
225165138Syongari				/*
226165138Syongari				 * We've been given a pointer
227165138Syongari				 * to a single buffer
228165138Syongari				 */
229165138Syongari				if ((ccb_h->flags & CAM_DATA_PHYS) == 0) {
230165138Syongari					int s;
231165138Syongari					int error;
232165138Syongari
233165138Syongari					s = splsoftvm();
234165138Syongari					error =
235165138Syongari					    bus_dmamap_load(adv->buffer_dmat,
236165138Syongari							    cinfo->dmamap,
237165138Syongari							    csio->data_ptr,
238165138Syongari							    csio->dxfer_len,
239165138Syongari							    adv_execute_ccb,
240165138Syongari							    csio, /*flags*/0);
241165138Syongari					if (error == EINPROGRESS) {
242165138Syongari						/*
243165138Syongari						 * So as to maintain ordering,
244165138Syongari						 * freeze the controller queue
245165138Syongari						 * until our mapping is
246165138Syongari						 * returned.
247165138Syongari						 */
248165138Syongari						adv_set_state(adv,
249165138Syongari							      ADV_BUSDMA_BLOCK);
250165138Syongari					}
251165138Syongari					splx(s);
252165138Syongari				} else {
253165138Syongari					struct bus_dma_segment seg;
254165138Syongari
255165138Syongari					/* Pointer to physical buffer */
256165138Syongari					seg.ds_addr =
257165138Syongari					     (bus_addr_t)csio->data_ptr;
258165138Syongari					seg.ds_len = csio->dxfer_len;
259165138Syongari					adv_execute_ccb(csio, &seg, 1, 0);
260165138Syongari				}
261165138Syongari			} else {
262165138Syongari				struct bus_dma_segment *segs;
263165138Syongari				if ((ccb_h->flags & CAM_DATA_PHYS) != 0)
264165138Syongari					panic("adv_setup_data - Physical "
265165138Syongari					      "segment pointers unsupported");
266165138Syongari
267165138Syongari				if ((ccb_h->flags & CAM_SG_LIST_PHYS) == 0)
268165138Syongari					panic("adv_setup_data - Virtual "
269165138Syongari					      "segment addresses unsupported");
270165138Syongari
271165138Syongari				/* Just use the segments provided */
272165138Syongari				segs = (struct bus_dma_segment *)csio->data_ptr;
273165138Syongari				adv_execute_ccb(ccb, segs, csio->sglist_cnt, 0);
274165138Syongari			}
275165138Syongari		} else {
276165138Syongari			adv_execute_ccb(ccb, NULL, 0, 0);
277165138Syongari		}
278165138Syongari		break;
279165138Syongari	}
280165138Syongari	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
281165138Syongari	case XPT_TARGET_IO:	/* Execute target I/O request */
282165138Syongari	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
283165138Syongari	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/
284165138Syongari	case XPT_EN_LUN:		/* Enable LUN as a target */
285165138Syongari	case XPT_ABORT:			/* Abort the specified CCB */
286165138Syongari		/* XXX Implement */
287165138Syongari		ccb->ccb_h.status = CAM_REQ_INVALID;
288165138Syongari		xpt_done(ccb);
289165138Syongari		break;
290165138Syongari	case XPT_SET_TRAN_SETTINGS:
291165138Syongari	{
292165138Syongari		struct	 ccb_trans_settings *cts;
293165138Syongari		target_bit_vector targ_mask;
294165138Syongari		struct adv_transinfo *tconf;
295165138Syongari		u_int	 update_type;
296165138Syongari		int	 s;
297165138Syongari
298165138Syongari		cts = &ccb->cts;
299165138Syongari		targ_mask = ADV_TID_TO_TARGET_MASK(cts->ccb_h.target_id);
300165138Syongari		update_type = 0;
301165138Syongari
302165138Syongari		/*
303165138Syongari		 * The user must specify which type of settings he wishes
304165138Syongari		 * to change.
305165138Syongari		 */
306165138Syongari		if (((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0)
307165138Syongari		 && ((cts->flags & CCB_TRANS_USER_SETTINGS) == 0)) {
308165138Syongari			tconf = &adv->tinfo[cts->ccb_h.target_id].current;
309165138Syongari			update_type |= ADV_TRANS_GOAL;
310165138Syongari		} else if (((cts->flags & CCB_TRANS_USER_SETTINGS) != 0)
311165138Syongari			&& ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) == 0)) {
312165138Syongari			tconf = &adv->tinfo[cts->ccb_h.target_id].user;
313165138Syongari			update_type |= ADV_TRANS_USER;
314165138Syongari		} else {
315165138Syongari			ccb->ccb_h.status = CAM_REQ_INVALID;
316165138Syongari			break;
317165138Syongari		}
318165138Syongari
319165138Syongari		s = splcam();
320165138Syongari
321165138Syongari		if ((update_type & ADV_TRANS_GOAL) != 0) {
322165138Syongari			if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) {
323165138Syongari				if ((cts->flags & CCB_TRANS_DISC_ENB) != 0)
324165138Syongari					adv->disc_enable |= targ_mask;
325165138Syongari				else
326165138Syongari					adv->disc_enable &= ~targ_mask;
327165138Syongari				adv_write_lram_8(adv, ADVV_DISC_ENABLE_B,
328165138Syongari						 adv->disc_enable);
329165138Syongari			}
330165138Syongari
331165138Syongari			if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) {
332165138Syongari				if ((cts->flags & CCB_TRANS_TAG_ENB) != 0)
333165138Syongari					adv->cmd_qng_enabled |= targ_mask;
334165138Syongari				else
335165138Syongari					adv->cmd_qng_enabled &= ~targ_mask;
336165138Syongari			}
337165138Syongari		}
338165138Syongari
339165138Syongari		if ((update_type & ADV_TRANS_USER) != 0) {
340165138Syongari			if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) {
341165138Syongari				if ((cts->flags & CCB_TRANS_DISC_ENB) != 0)
342165138Syongari					adv->user_disc_enable |= targ_mask;
343165138Syongari				else
344165138Syongari					adv->user_disc_enable &= ~targ_mask;
345165138Syongari			}
346165138Syongari
347165138Syongari			if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) {
348165138Syongari				if ((cts->flags & CCB_TRANS_TAG_ENB) != 0)
349165138Syongari					adv->user_cmd_qng_enabled |= targ_mask;
350165138Syongari				else
351165138Syongari					adv->user_cmd_qng_enabled &= ~targ_mask;
352165138Syongari			}
353165138Syongari		}
354165138Syongari
355165138Syongari		/*
356165138Syongari		 * If the user specifies either the sync rate, or offset,
357165138Syongari		 * but not both, the unspecified parameter defaults to its
358165138Syongari		 * current value in transfer negotiations.
359165138Syongari		 */
360165138Syongari		if (((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0)
361165138Syongari		 || ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)) {
362165138Syongari			/*
363165138Syongari			 * If the user provided a sync rate but no offset,
364165138Syongari			 * use the current offset.
365165138Syongari			 */
366165138Syongari			if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) == 0)
367165138Syongari				cts->sync_offset = tconf->offset;
368165138Syongari
369165138Syongari			/*
370165138Syongari			 * If the user provided an offset but no sync rate,
371165138Syongari			 * use the current sync rate.
372165138Syongari			 */
373165138Syongari			if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) == 0)
374165138Syongari				cts->sync_period = tconf->period;
375165138Syongari
376165138Syongari			adv_period_offset_to_sdtr(adv, &cts->sync_period,
377165138Syongari						  &cts->sync_offset,
378165138Syongari						  cts->ccb_h.target_id);
379165138Syongari
380165138Syongari			adv_set_syncrate(adv, /*struct cam_path */NULL,
381165138Syongari					 cts->ccb_h.target_id, cts->sync_period,
382165138Syongari					 cts->sync_offset, update_type);
383165138Syongari		}
384165138Syongari
385165138Syongari		splx(s);
386165138Syongari		ccb->ccb_h.status = CAM_REQ_CMP;
387165138Syongari		xpt_done(ccb);
388165138Syongari		break;
389165138Syongari	}
390165138Syongari	case XPT_GET_TRAN_SETTINGS:
391165138Syongari	/* Get default/user set transfer settings for the target */
392165138Syongari	{
393165138Syongari		struct ccb_trans_settings *cts;
394165138Syongari		struct adv_transinfo *tconf;
395165138Syongari		target_bit_vector target_mask;
396165138Syongari		int s;
397165138Syongari
398165138Syongari		cts = &ccb->cts;
399165138Syongari		target_mask = ADV_TID_TO_TARGET_MASK(cts->ccb_h.target_id);
400165138Syongari
401165138Syongari		cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB);
402165138Syongari
403165138Syongari		s = splcam();
404165138Syongari		if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) {
405165138Syongari			tconf = &adv->tinfo[cts->ccb_h.target_id].current;
406165138Syongari			if ((adv->disc_enable & target_mask) != 0)
407165138Syongari				cts->flags |= CCB_TRANS_DISC_ENB;
408165138Syongari			if ((adv->cmd_qng_enabled & target_mask) != 0)
409165138Syongari				cts->flags |= CCB_TRANS_TAG_ENB;
410165138Syongari		} else {
411165138Syongari			tconf = &adv->tinfo[cts->ccb_h.target_id].user;
412165138Syongari			if ((adv->user_disc_enable & target_mask) != 0)
413165138Syongari				cts->flags |= CCB_TRANS_DISC_ENB;
414165138Syongari			if ((adv->user_cmd_qng_enabled & target_mask) != 0)
415165138Syongari				cts->flags |= CCB_TRANS_TAG_ENB;
416165138Syongari		}
417165138Syongari
418165138Syongari		cts->sync_period = tconf->period;
419165138Syongari		cts->sync_offset = tconf->offset;
420165138Syongari		splx(s);
421165138Syongari
422165138Syongari		cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
423165138Syongari		cts->valid = CCB_TRANS_SYNC_RATE_VALID
424165138Syongari			   | CCB_TRANS_SYNC_OFFSET_VALID
425165138Syongari			   | CCB_TRANS_BUS_WIDTH_VALID
426165138Syongari			   | CCB_TRANS_DISC_VALID
427165138Syongari			   | CCB_TRANS_TQ_VALID;
428165138Syongari		ccb->ccb_h.status = CAM_REQ_CMP;
429165138Syongari		xpt_done(ccb);
430165138Syongari		break;
431165138Syongari	}
432165138Syongari	case XPT_CALC_GEOMETRY:
433165138Syongari	{
434165138Syongari		struct	  ccb_calc_geometry *ccg;
435165138Syongari		u_int32_t size_mb;
436165138Syongari		u_int32_t secs_per_cylinder;
437165138Syongari		int	  extended;
438165138Syongari
439165138Syongari		ccg = &ccb->ccg;
440165138Syongari		size_mb = ccg->volume_size
441165138Syongari			/ ((1024L * 1024L) / ccg->block_size);
442165138Syongari		extended = (adv->control & ADV_CNTL_BIOS_GT_1GB) != 0;
443165138Syongari
444165138Syongari		if (size_mb > 1024 && extended) {
445165138Syongari			ccg->heads = 255;
446165138Syongari			ccg->secs_per_track = 63;
447165138Syongari		} else {
448165138Syongari			ccg->heads = 64;
449165138Syongari			ccg->secs_per_track = 32;
450165138Syongari		}
451165138Syongari		secs_per_cylinder = ccg->heads * ccg->secs_per_track;
452165138Syongari		ccg->cylinders = ccg->volume_size / secs_per_cylinder;
453165138Syongari		ccb->ccb_h.status = CAM_REQ_CMP;
454165138Syongari		xpt_done(ccb);
455165138Syongari		break;
456165138Syongari	}
457165138Syongari	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
458165138Syongari	{
459165138Syongari		int s;
460165138Syongari
461165138Syongari		s = splcam();
462165138Syongari		adv_stop_execution(adv);
463165138Syongari		adv_reset_bus(adv, /*initiate_reset*/TRUE);
464165138Syongari		adv_start_execution(adv);
465165138Syongari		splx(s);
466165138Syongari
467165138Syongari		ccb->ccb_h.status = CAM_REQ_CMP;
468165138Syongari		xpt_done(ccb);
469165138Syongari		break;
470165138Syongari	}
471165138Syongari	case XPT_TERM_IO:		/* Terminate the I/O process */
472165138Syongari		/* XXX Implement */
473165138Syongari		ccb->ccb_h.status = CAM_REQ_INVALID;
474165138Syongari		xpt_done(ccb);
475165138Syongari		break;
476165138Syongari	case XPT_PATH_INQ:		/* Path routing inquiry */
477165138Syongari	{
478165138Syongari		struct ccb_pathinq *cpi = &ccb->cpi;
479165138Syongari
480165138Syongari		cpi->version_num = 1; /* XXX??? */
481165138Syongari		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE;
482165138Syongari		cpi->target_sprt = 0;
483165138Syongari		cpi->hba_misc = 0;
484165138Syongari		cpi->hba_eng_cnt = 0;
485165138Syongari		cpi->max_target = 7;
486165138Syongari		cpi->max_lun = 7;
487165138Syongari		cpi->initiator_id = adv->scsi_id;
488165138Syongari		cpi->bus_id = cam_sim_bus(sim);
489165138Syongari		cpi->base_transfer_speed = 3300;
490165138Syongari		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
491165138Syongari		strncpy(cpi->hba_vid, "Advansys", HBA_IDLEN);
492165138Syongari		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
493165138Syongari		cpi->unit_number = cam_sim_unit(sim);
494165138Syongari		cpi->ccb_h.status = CAM_REQ_CMP;
495165138Syongari		xpt_done(ccb);
496165138Syongari		break;
497165138Syongari	}
498165138Syongari	default:
499165138Syongari		ccb->ccb_h.status = CAM_REQ_INVALID;
500165138Syongari		xpt_done(ccb);
501165138Syongari		break;
502165138Syongari	}
503165138Syongari}
504165138Syongari
505165138Syongari/*
506165138Syongari * Currently, the output of bus_dmammap_load suits our needs just
507165138Syongari * fine, but should it change, we'd need to do something here.
508165138Syongari */
509165138Syongari#define adv_fixup_dmasegs(adv, dm_segs) (struct adv_sg_entry *)(dm_segs)
510165138Syongari
511165138Syongaristatic void
512165138Syongariadv_execute_ccb(void *arg, bus_dma_segment_t *dm_segs,
513165138Syongari		int nsegments, int error)
514165138Syongari{
515165138Syongari	struct	ccb_scsiio *csio;
516165138Syongari	struct	ccb_hdr *ccb_h;
517165138Syongari	struct	cam_sim *sim;
518165138Syongari        struct	adv_softc *adv;
519165138Syongari	struct	adv_ccb_info *cinfo;
520165138Syongari	struct	adv_scsi_q scsiq;
521165138Syongari	struct	adv_sg_head sghead;
522165138Syongari	int	s;
523165138Syongari
524165138Syongari	csio = (struct ccb_scsiio *)arg;
525165138Syongari	ccb_h = &csio->ccb_h;
526165138Syongari	sim = xpt_path_sim(ccb_h->path);
527165138Syongari	adv = (struct adv_softc *)cam_sim_softc(sim);
528165138Syongari	cinfo = (struct adv_ccb_info *)csio->ccb_h.ccb_cinfo_ptr;
529165138Syongari
530165138Syongari	/*
531165138Syongari	 * Setup our done routine to release the simq on
532165138Syongari	 * the next ccb that completes.
533165138Syongari	 */
534165138Syongari	if ((adv->state & ADV_BUSDMA_BLOCK) != 0)
535165138Syongari		adv->state |= ADV_BUSDMA_BLOCK_CLEARED;
536165138Syongari
537165138Syongari	if ((ccb_h->flags & CAM_CDB_POINTER) != 0) {
538165138Syongari		if ((ccb_h->flags & CAM_CDB_PHYS) == 0) {
539165138Syongari			/* XXX Need phystovirt!!!! */
540165138Syongari			/* How about pmap_kenter??? */
541165138Syongari			scsiq.cdbptr = csio->cdb_io.cdb_ptr;
542165138Syongari		} else {
543165138Syongari			scsiq.cdbptr = csio->cdb_io.cdb_ptr;
544165138Syongari		}
545165138Syongari	} else {
546165138Syongari		scsiq.cdbptr = csio->cdb_io.cdb_bytes;
547165138Syongari	}
548165138Syongari	/*
549165138Syongari	 * Build up the request
550165138Syongari	 */
551165138Syongari	scsiq.q1.status = 0;
552165138Syongari	scsiq.q1.q_no = 0;
553165138Syongari	scsiq.q1.cntl = 0;
554165138Syongari	scsiq.q1.sg_queue_cnt = 0;
555165138Syongari	scsiq.q1.target_id = ADV_TID_TO_TARGET_MASK(ccb_h->target_id);
556165138Syongari	scsiq.q1.target_lun = ccb_h->target_lun;
557165138Syongari	scsiq.q1.sense_len = csio->sense_len;
558165138Syongari	scsiq.q1.extra_bytes = 0;
559165138Syongari	scsiq.q2.ccb_index = cinfo - adv->ccb_infos;
560165138Syongari	scsiq.q2.target_ix = ADV_TIDLUN_TO_IX(ccb_h->target_id,
561165138Syongari					      ccb_h->target_lun);
562165138Syongari	scsiq.q2.flag = 0;
563165138Syongari	scsiq.q2.cdb_len = csio->cdb_len;
564165138Syongari	if ((ccb_h->flags & CAM_TAG_ACTION_VALID) != 0)
565165138Syongari		scsiq.q2.tag_code = csio->tag_action;
566165138Syongari	else
567165138Syongari		scsiq.q2.tag_code = 0;
568165138Syongari	scsiq.q2.vm_id = 0;
569165138Syongari
570165138Syongari	if (nsegments != 0) {
571165138Syongari		bus_dmasync_op_t op;
572165138Syongari
573165138Syongari		scsiq.q1.data_addr = dm_segs->ds_addr;
574165138Syongari                scsiq.q1.data_cnt = dm_segs->ds_len;
575165138Syongari		if (nsegments > 1) {
576165138Syongari			scsiq.q1.cntl |= QC_SG_HEAD;
577165138Syongari			sghead.entry_cnt
578165138Syongari			    = sghead.entry_to_copy
579165138Syongari			    = nsegments;
580165138Syongari			sghead.res = 0;
581165138Syongari			sghead.sg_list = adv_fixup_dmasegs(adv, dm_segs);
582165138Syongari			scsiq.sg_head = &sghead;
583165138Syongari		} else {
584165138Syongari			scsiq.sg_head = NULL;
585165138Syongari		}
586165138Syongari		if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN)
587165138Syongari			op = BUS_DMASYNC_PREREAD;
588165138Syongari		else
589165138Syongari			op = BUS_DMASYNC_PREWRITE;
590165138Syongari		bus_dmamap_sync(adv->buffer_dmat, cinfo->dmamap, op);
591165138Syongari	} else {
592165138Syongari		scsiq.q1.data_addr = 0;
593165138Syongari		scsiq.q1.data_cnt = 0;
594165138Syongari		scsiq.sg_head = NULL;
595165138Syongari	}
596165138Syongari
597165138Syongari	s = splcam();
598165138Syongari
599165138Syongari	/*
600165138Syongari	 * Last time we need to check if this SCB needs to
601165138Syongari	 * be aborted.
602165138Syongari	 */
603165138Syongari	if (ccb_h->status != CAM_REQ_INPROG) {
604165138Syongari		if (nsegments != 0)
605165138Syongari			bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap);
606165138Syongari		adv_clear_state(adv, (union ccb *)csio);
607165138Syongari		adv_free_ccb_info(adv, cinfo);
608165138Syongari		xpt_done((union ccb *)csio);
609165138Syongari		splx(s);
610165138Syongari		return;
611165138Syongari	}
612165138Syongari
613165138Syongari	if (adv_execute_scsi_queue(adv, &scsiq, csio->dxfer_len) != 0) {
614165138Syongari		/* Temporary resource shortage */
615165138Syongari		adv_set_state(adv, ADV_RESOURCE_SHORTAGE);
616165138Syongari		if (nsegments != 0)
617165138Syongari			bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap);
618165138Syongari		csio->ccb_h.status = CAM_REQUEUE_REQ;
619165138Syongari		adv_clear_state(adv, (union ccb *)csio);
620165138Syongari		adv_free_ccb_info(adv, cinfo);
621165138Syongari		xpt_done((union ccb *)csio);
622165138Syongari		splx(s);
623165138Syongari		return;
624165138Syongari	}
625165138Syongari	cinfo->state |= ACCB_ACTIVE;
626165138Syongari	ccb_h->status |= CAM_SIM_QUEUED;
627165138Syongari	LIST_INSERT_HEAD(&adv->pending_ccbs, ccb_h, sim_links.le);
628165138Syongari	/* Schedule our timeout */
629165138Syongari	ccb_h->timeout_ch =
630165138Syongari	    timeout(adv_timeout, csio, (ccb_h->timeout * hz)/1000);
631165138Syongari	splx(s);
632165138Syongari}
633165138Syongari
634165138Syongaristatic struct adv_ccb_info *
635165138Syongariadv_alloc_ccb_info(struct adv_softc *adv)
636165138Syongari{
637165138Syongari	int error;
638165138Syongari	struct adv_ccb_info *cinfo;
639165138Syongari
640165138Syongari	cinfo = &adv->ccb_infos[adv->ccb_infos_allocated];
641165138Syongari	cinfo->state = ACCB_FREE;
642165138Syongari	error = bus_dmamap_create(adv->buffer_dmat, /*flags*/0,
643165138Syongari				  &cinfo->dmamap);
644165138Syongari	if (error != 0) {
645165138Syongari		printf("%s: Unable to allocate CCB info "
646165138Syongari		       "dmamap - error %d\n", adv_name(adv), error);
647165138Syongari		return (NULL);
648165138Syongari	}
649165138Syongari	adv->ccb_infos_allocated++;
650165138Syongari	return (cinfo);
651165138Syongari}
652165138Syongari
653165138Syongaristatic void
654165138Syongariadv_destroy_ccb_info(struct adv_softc *adv, struct adv_ccb_info *cinfo)
655165138Syongari{
656165138Syongari	bus_dmamap_destroy(adv->buffer_dmat, cinfo->dmamap);
657165138Syongari}
658165138Syongari
659165138Syongarivoid
660165138Syongariadv_timeout(void *arg)
661165138Syongari{
662165138Syongari	int s;
663165138Syongari	union ccb *ccb;
664165138Syongari	struct adv_softc *adv;
665165138Syongari	struct adv_ccb_info *cinfo;
666165138Syongari
667165138Syongari	ccb = (union ccb *)arg;
668165138Syongari	adv = (struct adv_softc *)xpt_path_sim(ccb->ccb_h.path)->softc;
669165138Syongari	cinfo = (struct adv_ccb_info *)ccb->ccb_h.ccb_cinfo_ptr;
670165138Syongari
671165138Syongari	xpt_print_path(ccb->ccb_h.path);
672165138Syongari	printf("Timed out\n");
673165138Syongari
674165138Syongari	s = splcam();
675165138Syongari	/* Have we been taken care of already?? */
676165138Syongari	if (cinfo == NULL || cinfo->state == ACCB_FREE) {
677165138Syongari		splx(s);
678165138Syongari		return;
679165138Syongari	}
680165138Syongari
681165138Syongari	adv_stop_execution(adv);
682165138Syongari
683165138Syongari	if ((cinfo->state & ACCB_ABORT_QUEUED) == 0) {
684165138Syongari		struct ccb_hdr *ccb_h;
685165138Syongari
686165138Syongari		/*
687165138Syongari		 * In order to simplify the recovery process, we ask the XPT
688165138Syongari		 * layer to halt the queue of new transactions and we traverse
689165138Syongari		 * the list of pending CCBs and remove their timeouts. This
690165138Syongari		 * means that the driver attempts to clear only one error
691165138Syongari		 * condition at a time.  In general, timeouts that occur
692165138Syongari		 * close together are related anyway, so there is no benefit
693165138Syongari		 * in attempting to handle errors in parrallel.  Timeouts will
694165138Syongari		 * be reinstated when the recovery process ends.
695165138Syongari		 */
696165138Syongari		adv_set_state(adv, ADV_IN_TIMEOUT);
697165138Syongari
698165138Syongari		/* This CCB is the CCB representing our recovery actions */
699165138Syongari		cinfo->state |= ACCB_RECOVERY_CCB|ACCB_ABORT_QUEUED;
700165138Syongari
701165138Syongari		ccb_h = LIST_FIRST(&adv->pending_ccbs);
702165138Syongari		while (ccb_h != NULL) {
703165138Syongari			untimeout(adv_timeout, ccb_h, ccb_h->timeout_ch);
704165138Syongari			ccb_h = LIST_NEXT(ccb_h, sim_links.le);
705165138Syongari		}
706165138Syongari
707165138Syongari		/* XXX Should send a BDR */
708165138Syongari		/* Attempt an abort as our first tact */
709165138Syongari		xpt_print_path(ccb->ccb_h.path);
710165138Syongari		printf("Attempting abort\n");
711165138Syongari		adv_abort_ccb(adv, ccb->ccb_h.target_id,
712165138Syongari			      ccb->ccb_h.target_lun, ccb,
713165138Syongari			      CAM_CMD_TIMEOUT, /*queued_only*/FALSE);
714165138Syongari		ccb->ccb_h.timeout_ch =
715165138Syongari		    timeout(adv_timeout, ccb, 2 * hz);
716165138Syongari	} else {
717165138Syongari		/* Our attempt to perform an abort failed, go for a reset */
718165138Syongari		xpt_print_path(ccb->ccb_h.path);
719165138Syongari		printf("Resetting bus\n");
720165138Syongari		ccb->ccb_h.status &= ~CAM_STATUS_MASK;
721165138Syongari		ccb->ccb_h.status |= CAM_CMD_TIMEOUT;
722165138Syongari		adv_reset_bus(adv, /*initiate_reset*/TRUE);
723165138Syongari	}
724165138Syongari	adv_start_execution(adv);
725165138Syongari	splx(s);
726165138Syongari}
727165138Syongari
728165138Syongaristruct adv_softc *
729165138Syongariadv_alloc(device_t dev, bus_space_tag_t tag, bus_space_handle_t bsh)
730165138Syongari{
731165138Syongari	struct adv_softc *adv = device_get_softc(dev);
732165138Syongari
733165138Syongari	/*
734165138Syongari	 * Allocate a storage area for us
735165138Syongari	 */
736165138Syongari	LIST_INIT(&adv->pending_ccbs);
737165138Syongari	SLIST_INIT(&adv->free_ccb_infos);
738165138Syongari	adv->dev = dev;
739165138Syongari	adv->unit = device_get_unit(dev);
740165138Syongari	adv->tag = tag;
741165138Syongari	adv->bsh = bsh;
742165138Syongari
743165138Syongari	return(adv);
744165138Syongari}
745165138Syongari
746165138Syongarivoid
747165138Syongariadv_free(struct adv_softc *adv)
748165138Syongari{
749165138Syongari	switch (adv->init_level) {
750165138Syongari	case 6:
751165138Syongari	{
752165138Syongari		struct adv_ccb_info *cinfo;
753165138Syongari
754165138Syongari		while ((cinfo = SLIST_FIRST(&adv->free_ccb_infos)) != NULL) {
755165138Syongari			SLIST_REMOVE_HEAD(&adv->free_ccb_infos, links);
756165138Syongari			adv_destroy_ccb_info(adv, cinfo);
757165138Syongari		}
758165138Syongari
759165138Syongari		bus_dmamap_unload(adv->sense_dmat, adv->sense_dmamap);
760165138Syongari	}
761165138Syongari	case 5:
762165138Syongari		bus_dmamem_free(adv->sense_dmat, adv->sense_buffers,
763165138Syongari                                adv->sense_dmamap);
764165138Syongari	case 4:
765165138Syongari		bus_dma_tag_destroy(adv->sense_dmat);
766165138Syongari	case 3:
767165138Syongari		bus_dma_tag_destroy(adv->buffer_dmat);
768165138Syongari	case 2:
769165138Syongari		bus_dma_tag_destroy(adv->parent_dmat);
770165138Syongari	case 1:
771165138Syongari		if (adv->ccb_infos != NULL)
772165138Syongari			free(adv->ccb_infos, M_DEVBUF);
773165138Syongari	case 0:
774165138Syongari		break;
775165138Syongari	}
776165138Syongari}
777165138Syongari
778165138Syongariint
779165138Syongariadv_init(struct adv_softc *adv)
780165138Syongari{
781165138Syongari	struct	  adv_eeprom_config eeprom_config;
782165138Syongari	int	  checksum, i;
783165138Syongari	int	  max_sync;
784165138Syongari	u_int16_t config_lsw;
785165138Syongari	u_int16_t config_msw;
786165138Syongari
787165138Syongari	adv_lib_init(adv);
788165138Syongari
789165138Syongari  	/*
790165138Syongari	 * Stop script execution.
791165138Syongari	 */
792165138Syongari	adv_write_lram_16(adv, ADV_HALTCODE_W, 0x00FE);
793165138Syongari	adv_stop_execution(adv);
794165138Syongari	if (adv_stop_chip(adv) == 0 || adv_is_chip_halted(adv) == 0) {
795165138Syongari		printf("adv%d: Unable to halt adapter. Initialization"
796165138Syongari		       "failed\n", adv->unit);
797165138Syongari		return (1);
798165138Syongari	}
799165138Syongari	ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR);
800165138Syongari	if (ADV_INW(adv, ADV_REG_PROG_COUNTER) != ADV_MCODE_START_ADDR) {
801165138Syongari		printf("adv%d: Unable to set program counter. Initialization"
802165138Syongari		       "failed\n", adv->unit);
803165138Syongari		return (1);
804165138Syongari	}
805165138Syongari
806165138Syongari	config_msw = ADV_INW(adv, ADV_CONFIG_MSW);
807165138Syongari	config_lsw = ADV_INW(adv, ADV_CONFIG_LSW);
808165138Syongari
809165138Syongari	if ((config_msw & ADV_CFG_MSW_CLR_MASK) != 0) {
810165138Syongari		config_msw &= ~ADV_CFG_MSW_CLR_MASK;
811165138Syongari		/*
812165138Syongari		 * XXX The Linux code flags this as an error,
813165138Syongari		 * but what should we report to the user???
814165138Syongari		 * It seems that clearing the config register
815165138Syongari		 * makes this error recoverable.
816165138Syongari		 */
817165138Syongari		ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw);
818165138Syongari	}
819165138Syongari
820165138Syongari	/* Suck in the configuration from the EEProm */
821165138Syongari	checksum = adv_get_eeprom_config(adv, &eeprom_config);
822165138Syongari
823165138Syongari	if (ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_AUTO_CONFIG) {
824165138Syongari		/*
825165138Syongari		 * XXX The Linux code sets a warning level for this
826165138Syongari		 * condition, yet nothing of meaning is printed to
827165138Syongari		 * the user.  What does this mean???
828165138Syongari		 */
829165138Syongari		if (adv->chip_version == 3) {
830165138Syongari			if (eeprom_config.cfg_lsw != config_lsw)
831165138Syongari				eeprom_config.cfg_lsw = config_lsw;
832165138Syongari			if (eeprom_config.cfg_msw != config_msw) {
833165138Syongari				eeprom_config.cfg_msw = config_msw;
834165138Syongari			}
835165138Syongari		}
836165138Syongari	}
837165138Syongari	if (checksum == eeprom_config.chksum) {
838165138Syongari
839165138Syongari		/* Range/Sanity checking */
840165138Syongari		if (eeprom_config.max_total_qng < ADV_MIN_TOTAL_QNG) {
841165138Syongari			eeprom_config.max_total_qng = ADV_MIN_TOTAL_QNG;
842165138Syongari		}
843165138Syongari		if (eeprom_config.max_total_qng > ADV_MAX_TOTAL_QNG) {
844165138Syongari			eeprom_config.max_total_qng = ADV_MAX_TOTAL_QNG;
845165138Syongari		}
846165138Syongari		if (eeprom_config.max_tag_qng > eeprom_config.max_total_qng) {
847165138Syongari			eeprom_config.max_tag_qng = eeprom_config.max_total_qng;
848165138Syongari		}
849165138Syongari		if (eeprom_config.max_tag_qng < ADV_MIN_TAG_Q_PER_DVC) {
850165138Syongari			eeprom_config.max_tag_qng = ADV_MIN_TAG_Q_PER_DVC;
851165138Syongari		}
852165138Syongari		adv->max_openings = eeprom_config.max_total_qng;
853165138Syongari		adv->user_disc_enable = eeprom_config.disc_enable;
854165138Syongari		adv->user_cmd_qng_enabled = eeprom_config.use_cmd_qng;
855165138Syongari		adv->isa_dma_speed = EEPROM_DMA_SPEED(eeprom_config);
856165138Syongari		adv->scsi_id = EEPROM_SCSIID(eeprom_config) & ADV_MAX_TID;
857165138Syongari		EEPROM_SET_SCSIID(eeprom_config, adv->scsi_id);
858165138Syongari		adv->control = eeprom_config.cntl;
859165138Syongari		for (i = 0; i <= ADV_MAX_TID; i++) {
860165138Syongari			u_int8_t sync_data;
861165138Syongari
862165138Syongari			if ((eeprom_config.init_sdtr & (0x1 << i)) == 0)
863165138Syongari				sync_data = 0;
864165138Syongari			else
865165138Syongari				sync_data = eeprom_config.sdtr_data[i];
866165138Syongari			adv_sdtr_to_period_offset(adv,
867165138Syongari						  sync_data,
868165138Syongari						  &adv->tinfo[i].user.period,
869165138Syongari						  &adv->tinfo[i].user.offset,
870165138Syongari						  i);
871165138Syongari		}
872165138Syongari		config_lsw = eeprom_config.cfg_lsw;
873165138Syongari		eeprom_config.cfg_msw = config_msw;
874165138Syongari	} else {
875165138Syongari		u_int8_t sync_data;
876165138Syongari
877165138Syongari		printf("adv%d: Warning EEPROM Checksum mismatch. "
878165138Syongari		       "Using default device parameters\n", adv->unit);
879165138Syongari
880165138Syongari		/* Set reasonable defaults since we can't read the EEPROM */
881165138Syongari		adv->isa_dma_speed = /*ADV_DEF_ISA_DMA_SPEED*/1;
882165138Syongari		adv->max_openings = ADV_DEF_MAX_TOTAL_QNG;
883165138Syongari		adv->disc_enable = TARGET_BIT_VECTOR_SET;
884165138Syongari		adv->user_disc_enable = TARGET_BIT_VECTOR_SET;
885165138Syongari		adv->cmd_qng_enabled = TARGET_BIT_VECTOR_SET;
886165138Syongari		adv->user_cmd_qng_enabled = TARGET_BIT_VECTOR_SET;
887165138Syongari		adv->scsi_id = 7;
888165138Syongari		adv->control = 0xFFFF;
889165138Syongari
890165138Syongari		if (adv->chip_version == ADV_CHIP_VER_PCI_ULTRA_3050)
891165138Syongari			/* Default to no Ultra to support the 3030 */
892165138Syongari			adv->control &= ~ADV_CNTL_SDTR_ENABLE_ULTRA;
893165138Syongari		sync_data = ADV_DEF_SDTR_OFFSET | (ADV_DEF_SDTR_INDEX << 4);
894165138Syongari		for (i = 0; i <= ADV_MAX_TID; i++) {
895165138Syongari			adv_sdtr_to_period_offset(adv, sync_data,
896165138Syongari						  &adv->tinfo[i].user.period,
897165138Syongari						  &adv->tinfo[i].user.offset,
898165138Syongari						  i);
899165138Syongari		}
900165138Syongari		config_lsw |= ADV_CFG_LSW_SCSI_PARITY_ON;
901165138Syongari	}
902165138Syongari	config_msw &= ~ADV_CFG_MSW_CLR_MASK;
903165138Syongari	config_lsw |= ADV_CFG_LSW_HOST_INT_ON;
904165138Syongari	if ((adv->type & (ADV_PCI|ADV_ULTRA)) == (ADV_PCI|ADV_ULTRA)
905165138Syongari	 && (adv->control & ADV_CNTL_SDTR_ENABLE_ULTRA) == 0)
906165138Syongari		/* 25ns or 10MHz */
907165138Syongari		max_sync = 25;
908165138Syongari	else
909165138Syongari		/* Unlimited */
910165138Syongari		max_sync = 0;
911165138Syongari	for (i = 0; i <= ADV_MAX_TID; i++) {
912165138Syongari		if (adv->tinfo[i].user.period < max_sync)
913165138Syongari			adv->tinfo[i].user.period = max_sync;
914165138Syongari	}
915165138Syongari
916165138Syongari	if (adv_test_external_lram(adv) == 0) {
917165138Syongari		if ((adv->type & (ADV_PCI|ADV_ULTRA)) == (ADV_PCI|ADV_ULTRA)) {
918165138Syongari			eeprom_config.max_total_qng =
919165138Syongari			    ADV_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
920165138Syongari			eeprom_config.max_tag_qng =
921165138Syongari			    ADV_MAX_PCI_ULTRA_INRAM_TAG_QNG;
922165138Syongari		} else {
923165138Syongari			eeprom_config.cfg_msw |= 0x0800;
924165138Syongari			config_msw |= 0x0800;
925165138Syongari			eeprom_config.max_total_qng =
926165138Syongari			     ADV_MAX_PCI_INRAM_TOTAL_QNG;
927165138Syongari			eeprom_config.max_tag_qng = ADV_MAX_INRAM_TAG_QNG;
928165138Syongari		}
929165138Syongari		adv->max_openings = eeprom_config.max_total_qng;
930165138Syongari	}
931165138Syongari	ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw);
932165138Syongari	ADV_OUTW(adv, ADV_CONFIG_LSW, config_lsw);
933165138Syongari#if 0
934165138Syongari	/*
935165138Syongari	 * Don't write the eeprom data back for now.
936165138Syongari	 * I'd rather not mess up the user's card.  We also don't
937165138Syongari	 * fully sanitize the eeprom settings above for the write-back
938165138Syongari	 * to be 100% correct.
939165138Syongari	 */
940165138Syongari	if (adv_set_eeprom_config(adv, &eeprom_config) != 0)
941165138Syongari		printf("%s: WARNING! Failure writing to EEPROM.\n",
942165138Syongari		       adv_name(adv));
943165138Syongari#endif
944165138Syongari
945165138Syongari	adv_set_chip_scsiid(adv, adv->scsi_id);
946165138Syongari	if (adv_init_lram_and_mcode(adv))
947165138Syongari		return (1);
948165138Syongari
949165138Syongari	adv->disc_enable = adv->user_disc_enable;
950165138Syongari
951165138Syongari	adv_write_lram_8(adv, ADVV_DISC_ENABLE_B, adv->disc_enable);
952165138Syongari	for (i = 0; i <= ADV_MAX_TID; i++) {
953165138Syongari		/*
954165138Syongari		 * Start off in async mode.
955165138Syongari		 */
956165138Syongari		adv_set_syncrate(adv, /*struct cam_path */NULL,
957165138Syongari				 i, /*period*/0, /*offset*/0,
958165138Syongari				 ADV_TRANS_CUR);
959165138Syongari		/*
960165138Syongari		 * Enable the use of tagged commands on all targets.
961165138Syongari		 * This allows the kernel driver to make up it's own mind
962165138Syongari		 * as it sees fit to tag queue instead of having the
963165138Syongari		 * firmware try and second guess the tag_code settins.
964165138Syongari		 */
965165138Syongari		adv_write_lram_8(adv, ADVV_MAX_DVC_QNG_BEG + i,
966165138Syongari				 adv->max_openings);
967165138Syongari	}
968165138Syongari	adv_write_lram_8(adv, ADVV_USE_TAGGED_QNG_B, TARGET_BIT_VECTOR_SET);
969165138Syongari	adv_write_lram_8(adv, ADVV_CAN_TAGGED_QNG_B, TARGET_BIT_VECTOR_SET);
970165138Syongari	printf("adv%d: AdvanSys %s Host Adapter, SCSI ID %d, queue depth %d\n",
971165138Syongari	       adv->unit, (adv->type & ADV_ULTRA) && (max_sync == 0)
972165138Syongari			  ? "Ultra SCSI" : "SCSI",
973165138Syongari	       adv->scsi_id, adv->max_openings);
974165138Syongari	return (0);
975165138Syongari}
976165138Syongari
977165138Syongarivoid
978165138Syongariadv_intr(void *arg)
979165138Syongari{
980165138Syongari	struct	  adv_softc *adv;
981165138Syongari	u_int16_t chipstat;
982165138Syongari	u_int16_t saved_ram_addr;
983165138Syongari	u_int8_t  ctrl_reg;
984165138Syongari	u_int8_t  saved_ctrl_reg;
985165138Syongari	u_int8_t  host_flag;
986165138Syongari
987165138Syongari	adv = (struct adv_softc *)arg;
988165138Syongari
989165138Syongari	chipstat = ADV_INW(adv, ADV_CHIP_STATUS);
990165138Syongari
991165138Syongari	/* Is it for us? */
992165138Syongari	if ((chipstat & (ADV_CSW_INT_PENDING|ADV_CSW_SCSI_RESET_LATCH)) == 0)
993165138Syongari		return;
994165138Syongari
995165138Syongari	ctrl_reg = ADV_INB(adv, ADV_CHIP_CTRL);
996165138Syongari	saved_ctrl_reg = ctrl_reg & (~(ADV_CC_SCSI_RESET | ADV_CC_CHIP_RESET |
997165138Syongari				       ADV_CC_SINGLE_STEP | ADV_CC_DIAG |
998165138Syongari				       ADV_CC_TEST));
999165138Syongari
1000165138Syongari	if ((chipstat & (ADV_CSW_SCSI_RESET_LATCH|ADV_CSW_SCSI_RESET_ACTIVE))) {
1001165138Syongari		printf("Detected Bus Reset\n");
1002165138Syongari		adv_reset_bus(adv, /*initiate_reset*/FALSE);
1003165138Syongari		return;
1004165138Syongari	}
1005165138Syongari
1006165138Syongari	if ((chipstat & ADV_CSW_INT_PENDING) != 0) {
1007165138Syongari
1008165138Syongari		saved_ram_addr = ADV_INW(adv, ADV_LRAM_ADDR);
1009165138Syongari		host_flag = adv_read_lram_8(adv, ADVV_HOST_FLAG_B);
1010165138Syongari		adv_write_lram_8(adv, ADVV_HOST_FLAG_B,
1011165138Syongari				 host_flag | ADV_HOST_FLAG_IN_ISR);
1012165138Syongari
1013165138Syongari		adv_ack_interrupt(adv);
1014165138Syongari
1015165138Syongari		if ((chipstat & ADV_CSW_HALTED) != 0
1016165138Syongari		 && (ctrl_reg & ADV_CC_SINGLE_STEP) != 0) {
1017165138Syongari			adv_isr_chip_halted(adv);
1018165138Syongari			saved_ctrl_reg &= ~ADV_CC_HALT;
1019165138Syongari		} else {
1020165138Syongari			adv_run_doneq(adv);
1021165138Syongari		}
1022165138Syongari		ADV_OUTW(adv, ADV_LRAM_ADDR, saved_ram_addr);
1023165138Syongari#ifdef DIAGNOSTIC
1024165138Syongari		if (ADV_INW(adv, ADV_LRAM_ADDR) != saved_ram_addr)
1025165138Syongari			panic("adv_intr: Unable to set LRAM addr");
1026165138Syongari#endif
1027165138Syongari		adv_write_lram_8(adv, ADVV_HOST_FLAG_B, host_flag);
1028165138Syongari	}
1029165138Syongari
1030165138Syongari	ADV_OUTB(adv, ADV_CHIP_CTRL, saved_ctrl_reg);
1031165138Syongari}
1032165138Syongari
1033165138Syongaristatic void
1034165138Syongariadv_run_doneq(struct adv_softc *adv)
1035165138Syongari{
1036165138Syongari	struct adv_q_done_info scsiq;
1037165138Syongari	u_int		  doneq_head;
1038165138Syongari	u_int		  done_qno;
1039165138Syongari
1040165138Syongari	doneq_head = adv_read_lram_16(adv, ADVV_DONE_Q_TAIL_W) & 0xFF;
1041165138Syongari	done_qno = adv_read_lram_8(adv, ADV_QNO_TO_QADDR(doneq_head)
1042165138Syongari				   + ADV_SCSIQ_B_FWD);
1043165138Syongari	while (done_qno != ADV_QLINK_END) {
1044165138Syongari		union ccb* ccb;
1045165138Syongari		struct adv_ccb_info *cinfo;
1046165138Syongari		u_int done_qaddr;
1047165138Syongari		u_int sg_queue_cnt;
1048165138Syongari		int   aborted;
1049165138Syongari
1050165138Syongari		done_qaddr = ADV_QNO_TO_QADDR(done_qno);
1051165138Syongari
1052165138Syongari		/* Pull status from this request */
1053165138Syongari		sg_queue_cnt = adv_copy_lram_doneq(adv, done_qaddr, &scsiq,
1054165138Syongari						   adv->max_dma_count);
1055165138Syongari
1056165138Syongari		/* Mark it as free */
1057165138Syongari		adv_write_lram_8(adv, done_qaddr + ADV_SCSIQ_B_STATUS,
1058165138Syongari				 scsiq.q_status & ~(QS_READY|QS_ABORTED));
1059165138Syongari
1060165138Syongari		/* Process request based on retrieved info */
1061165138Syongari		if ((scsiq.cntl & QC_SG_HEAD) != 0) {
1062165138Syongari			u_int i;
1063165138Syongari
1064165138Syongari			/*
1065165138Syongari			 * S/G based request.  Free all of the queue
1066165138Syongari			 * structures that contained S/G information.
1067165138Syongari			 */
1068165138Syongari			for (i = 0; i < sg_queue_cnt; i++) {
1069165138Syongari				done_qno = adv_read_lram_8(adv, done_qaddr
1070165138Syongari							   + ADV_SCSIQ_B_FWD);
1071165138Syongari
1072165138Syongari#ifdef DIAGNOSTIC
1073165138Syongari				if (done_qno == ADV_QLINK_END) {
1074165138Syongari					panic("adv_qdone: Corrupted SG "
1075165138Syongari					      "list encountered");
1076165138Syongari				}
1077165138Syongari#endif
1078165138Syongari				done_qaddr = ADV_QNO_TO_QADDR(done_qno);
1079165138Syongari
1080165138Syongari				/* Mark SG queue as free */
1081165138Syongari				adv_write_lram_8(adv, done_qaddr
1082165138Syongari						 + ADV_SCSIQ_B_STATUS, QS_FREE);
1083165138Syongari			}
1084165138Syongari		} else
1085165138Syongari			sg_queue_cnt = 0;
1086165138Syongari#ifdef DIAGNOSTIC
1087165138Syongari		if (adv->cur_active < (sg_queue_cnt + 1))
1088165138Syongari			panic("adv_qdone: Attempting to free more "
1089165138Syongari			      "queues than are active");
1090165138Syongari#endif
1091165138Syongari		adv->cur_active -= sg_queue_cnt + 1;
1092165138Syongari
1093165138Syongari		aborted = (scsiq.q_status & QS_ABORTED) != 0;
1094165138Syongari
1095165138Syongari		if ((scsiq.q_status != QS_DONE)
1096165138Syongari		 && (scsiq.q_status & QS_ABORTED) == 0)
1097165138Syongari			panic("adv_qdone: completed scsiq with unknown status");
1098165138Syongari
1099165138Syongari		scsiq.remain_bytes += scsiq.extra_bytes;
1100165138Syongari
1101165138Syongari		if ((scsiq.d3.done_stat == QD_WITH_ERROR) &&
1102165138Syongari		    (scsiq.d3.host_stat == QHSTA_M_DATA_OVER_RUN)) {
1103165138Syongari			if ((scsiq.cntl & (QC_DATA_IN|QC_DATA_OUT)) == 0) {
1104165138Syongari				scsiq.d3.done_stat = QD_NO_ERROR;
1105165138Syongari				scsiq.d3.host_stat = QHSTA_NO_ERROR;
1106165138Syongari			}
1107165138Syongari		}
1108165138Syongari
1109165138Syongari		cinfo = &adv->ccb_infos[scsiq.d2.ccb_index];
1110165138Syongari		ccb = cinfo->ccb;
1111165138Syongari		ccb->csio.resid = scsiq.remain_bytes;
1112165138Syongari		adv_done(adv, ccb,
1113165138Syongari			 scsiq.d3.done_stat, scsiq.d3.host_stat,
1114165138Syongari			 scsiq.d3.scsi_stat, scsiq.q_no);
1115165138Syongari
1116165138Syongari		doneq_head = done_qno;
1117165138Syongari		done_qno = adv_read_lram_8(adv, done_qaddr + ADV_SCSIQ_B_FWD);
1118165138Syongari	}
1119165138Syongari	adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, doneq_head);
1120165138Syongari}
1121165138Syongari
1122165138Syongari
1123165138Syongarivoid
1124165138Syongariadv_done(struct adv_softc *adv, union ccb *ccb, u_int done_stat,
1125165138Syongari	 u_int host_stat, u_int scsi_status, u_int q_no)
1126165138Syongari{
1127165138Syongari	struct	   adv_ccb_info *cinfo;
1128165138Syongari
1129165138Syongari	cinfo = (struct adv_ccb_info *)ccb->ccb_h.ccb_cinfo_ptr;
1130165138Syongari	LIST_REMOVE(&ccb->ccb_h, sim_links.le);
1131165138Syongari	untimeout(adv_timeout, ccb, ccb->ccb_h.timeout_ch);
1132165138Syongari	if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
1133165138Syongari		bus_dmasync_op_t op;
1134165138Syongari
1135165138Syongari		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
1136165138Syongari			op = BUS_DMASYNC_POSTREAD;
1137165138Syongari		else
1138165138Syongari			op = BUS_DMASYNC_POSTWRITE;
1139165138Syongari		bus_dmamap_sync(adv->buffer_dmat, cinfo->dmamap, op);
1140165138Syongari		bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap);
1141165138Syongari	}
1142165138Syongari
1143165138Syongari	switch (done_stat) {
1144165138Syongari	case QD_NO_ERROR:
1145165138Syongari		if (host_stat == QHSTA_NO_ERROR) {
1146165138Syongari			ccb->ccb_h.status = CAM_REQ_CMP;
1147165138Syongari			break;
1148165138Syongari		}
1149165138Syongari		xpt_print_path(ccb->ccb_h.path);
1150165138Syongari		printf("adv_done - queue done without error, "
1151165138Syongari		       "but host status non-zero(%x)\n", host_stat);
1152165138Syongari		/*FALLTHROUGH*/
1153165138Syongari	case QD_WITH_ERROR:
1154165138Syongari		switch (host_stat) {
1155165138Syongari		case QHSTA_M_TARGET_STATUS_BUSY:
1156165138Syongari		case QHSTA_M_BAD_QUEUE_FULL_OR_BUSY:
1157165138Syongari			/*
1158165138Syongari			 * Assume that if we were a tagged transaction
1159165138Syongari			 * the target reported queue full.  Otherwise,
1160165138Syongari			 * report busy.  The firmware really should just
1161165138Syongari			 * pass the original status back up to us even
1162165138Syongari			 * if it thinks the target was in error for
1163165138Syongari			 * returning this status as no other transactions
1164165138Syongari			 * from this initiator are in effect, but this
1165165138Syongari			 * ignores multi-initiator setups and there is
1166165138Syongari			 * evidence that the firmware gets its per-device
1167165138Syongari			 * transaction counts screwed up occassionally.
1168165138Syongari			 */
1169165138Syongari			ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
1170165138Syongari			if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0
1171165138Syongari			 && host_stat != QHSTA_M_TARGET_STATUS_BUSY)
1172165138Syongari				scsi_status = SCSI_STATUS_QUEUE_FULL;
1173165138Syongari			else
1174165138Syongari				scsi_status = SCSI_STATUS_BUSY;
1175165138Syongari			adv_abort_ccb(adv, ccb->ccb_h.target_id,
1176165138Syongari				      ccb->ccb_h.target_lun,
1177165138Syongari				      /*ccb*/NULL, CAM_REQUEUE_REQ,
1178165138Syongari				      /*queued_only*/TRUE);
1179165138Syongari			/*FALLTHROUGH*/
1180165138Syongari		case QHSTA_M_NO_AUTO_REQ_SENSE:
1181165138Syongari		case QHSTA_NO_ERROR:
1182165138Syongari			ccb->csio.scsi_status = scsi_status;
1183165138Syongari			switch (scsi_status) {
1184165138Syongari			case SCSI_STATUS_CHECK_COND:
1185165138Syongari			case SCSI_STATUS_CMD_TERMINATED:
1186165138Syongari				ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
1187165138Syongari				/* Structure copy */
1188165138Syongari				ccb->csio.sense_data =
1189165138Syongari				    adv->sense_buffers[q_no - 1];
1190165138Syongari				/* FALLTHROUGH */
1191165138Syongari			case SCSI_STATUS_BUSY:
1192165138Syongari			case SCSI_STATUS_RESERV_CONFLICT:
1193165138Syongari			case SCSI_STATUS_QUEUE_FULL:
1194165138Syongari			case SCSI_STATUS_COND_MET:
1195165138Syongari			case SCSI_STATUS_INTERMED:
1196165138Syongari			case SCSI_STATUS_INTERMED_COND_MET:
1197165138Syongari				ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
1198165138Syongari				break;
1199165138Syongari			case SCSI_STATUS_OK:
1200165138Syongari				ccb->ccb_h.status |= CAM_REQ_CMP;
1201165138Syongari				break;
1202165138Syongari			}
1203165138Syongari			break;
1204165138Syongari		case QHSTA_M_SEL_TIMEOUT:
1205165138Syongari			ccb->ccb_h.status = CAM_SEL_TIMEOUT;
1206165138Syongari			break;
1207165138Syongari		case QHSTA_M_DATA_OVER_RUN:
1208165138Syongari			ccb->ccb_h.status = CAM_DATA_RUN_ERR;
1209165138Syongari			break;
1210165138Syongari		case QHSTA_M_UNEXPECTED_BUS_FREE:
1211165138Syongari			ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
1212165138Syongari			break;
1213165138Syongari		case QHSTA_M_BAD_BUS_PHASE_SEQ:
1214165138Syongari			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
1215165138Syongari			break;
1216165138Syongari		case QHSTA_M_BAD_CMPL_STATUS_IN:
1217165138Syongari			/* No command complete after a status message */
1218165138Syongari			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
1219165138Syongari			break;
1220165138Syongari		case QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT:
1221165138Syongari		case QHSTA_M_WTM_TIMEOUT:
1222165138Syongari		case QHSTA_M_HUNG_REQ_SCSI_BUS_RESET:
1223165138Syongari			/* The SCSI bus hung in a phase */
1224165138Syongari			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
1225165138Syongari			adv_reset_bus(adv, /*initiate_reset*/TRUE);
1226165138Syongari			break;
1227165138Syongari		case QHSTA_M_AUTO_REQ_SENSE_FAIL:
1228165138Syongari			ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
1229165138Syongari			break;
1230165138Syongari		case QHSTA_D_QDONE_SG_LIST_CORRUPTED:
1231165138Syongari		case QHSTA_D_ASC_DVC_ERROR_CODE_SET:
1232165138Syongari		case QHSTA_D_HOST_ABORT_FAILED:
1233165138Syongari		case QHSTA_D_EXE_SCSI_Q_FAILED:
1234165138Syongari		case QHSTA_D_ASPI_NO_BUF_POOL:
1235165138Syongari		case QHSTA_M_BAD_TAG_CODE:
1236165138Syongari		case QHSTA_D_LRAM_CMP_ERROR:
1237165138Syongari		case QHSTA_M_MICRO_CODE_ERROR_HALT:
1238165138Syongari		default:
1239165138Syongari			panic("%s: Unhandled Host status error %x",
1240165138Syongari			      adv_name(adv), host_stat);
1241165138Syongari			/* NOTREACHED */
1242165138Syongari		}
1243165138Syongari		break;
1244165138Syongari
1245165138Syongari	case QD_ABORTED_BY_HOST:
1246165138Syongari		/* Don't clobber any, more explicit, error codes we've set */
1247165138Syongari		if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG)
1248165138Syongari			ccb->ccb_h.status = CAM_REQ_ABORTED;
1249165138Syongari		break;
1250165138Syongari
1251165138Syongari	default:
1252165138Syongari		xpt_print_path(ccb->ccb_h.path);
1253165138Syongari		printf("adv_done - queue done with unknown status %x:%x\n",
1254165138Syongari		       done_stat, host_stat);
1255165138Syongari		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
1256165138Syongari		break;
1257165138Syongari	}
1258165138Syongari	adv_clear_state(adv, ccb);
1259165138Syongari	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP
1260165138Syongari	 && (ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
1261165138Syongari		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
1262165138Syongari		ccb->ccb_h.status |= CAM_DEV_QFRZN;
1263165138Syongari	}
1264165138Syongari	adv_free_ccb_info(adv, cinfo);
1265165138Syongari	/*
1266165138Syongari	 * Null this out so that we catch driver bugs that cause a
1267165138Syongari	 * ccb to be completed twice.
1268165138Syongari	 */
1269165138Syongari	ccb->ccb_h.ccb_cinfo_ptr = NULL;
1270165138Syongari	ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
1271165138Syongari	xpt_done(ccb);
1272165138Syongari}
1273165138Syongari
1274165138Syongari/*
1275165138Syongari * Function to poll for command completion when
1276165138Syongari * interrupts are disabled (crash dumps)
1277165138Syongari */
1278165138Syongaristatic void
1279165138Syongariadv_poll(struct cam_sim *sim)
1280165138Syongari{
1281165138Syongari	adv_intr(cam_sim_softc(sim));
1282165138Syongari}
1283165138Syongari
1284165138Syongari/*
1285165138Syongari * Attach all the sub-devices we can find
1286165138Syongari */
1287165138Syongariint
1288165138Syongariadv_attach(adv)
1289165138Syongari	struct adv_softc *adv;
1290165138Syongari{
1291165138Syongari	struct ccb_setasync csa;
1292165138Syongari	struct cam_devq *devq;
1293165138Syongari	int max_sg;
1294165138Syongari
1295165138Syongari	/*
1296165138Syongari	 * Allocate an array of ccb mapping structures.  We put the
1297165138Syongari	 * index of the ccb_info structure into the queue representing
1298165138Syongari	 * a transaction and use it for mapping the queue to the
1299165138Syongari	 * upper level SCSI transaction it represents.
1300165138Syongari	 */
1301165138Syongari	adv->ccb_infos = malloc(sizeof(*adv->ccb_infos) * adv->max_openings,
1302165138Syongari				M_DEVBUF, M_NOWAIT);
1303165138Syongari
1304165138Syongari	if (adv->ccb_infos == NULL)
1305165138Syongari		return (ENOMEM);
1306165138Syongari
1307165138Syongari	adv->init_level++;
1308165138Syongari
1309165138Syongari	/*
1310165138Syongari	 * Create our DMA tags.  These tags define the kinds of device
1311165138Syongari	 * accessible memory allocations and memory mappings we will
1312165138Syongari	 * need to perform during normal operation.
1313165138Syongari	 *
1314165138Syongari	 * Unless we need to further restrict the allocation, we rely
1315165138Syongari	 * on the restrictions of the parent dmat, hence the common
1316165138Syongari	 * use of MAXADDR and MAXSIZE.
1317165138Syongari	 *
1318165138Syongari	 * The ASC boards use chains of "queues" (the transactional
1319165138Syongari	 * resources on the board) to represent long S/G lists.
1320165138Syongari	 * The first queue represents the command and holds a
1321165138Syongari	 * single address and data pair.  The queues that follow
1322165138Syongari	 * can each hold ADV_SG_LIST_PER_Q entries.  Given the
1323165138Syongari	 * total number of queues, we can express the largest
1324165138Syongari	 * transaction we can map.  We reserve a few queues for
1325165138Syongari	 * error recovery.  Take those into account as well.
1326165138Syongari	 *
1327165138Syongari	 * There is a way to take an interrupt to download the
1328165138Syongari	 * next batch of S/G entries if there are more than 255
1329165138Syongari	 * of them (the counter in the queue structure is a u_int8_t).
1330165138Syongari	 * We don't use this feature, so limit the S/G list size
1331165138Syongari	 * accordingly.
1332165138Syongari	 */
1333165138Syongari	max_sg = (adv->max_openings - ADV_MIN_FREE_Q - 1) * ADV_SG_LIST_PER_Q;
1334165138Syongari	if (max_sg > 255)
1335165138Syongari		max_sg = 255;
1336165138Syongari
1337165138Syongari	/* DMA tag for mapping buffers into device visible space. */
1338165138Syongari	if (bus_dma_tag_create(
1339165138Syongari			/* parent	*/ adv->parent_dmat,
1340165138Syongari			/* alignment	*/ 1,
1341165138Syongari			/* boundary	*/ 0,
1342165138Syongari			/* lowaddr	*/ BUS_SPACE_MAXADDR,
1343165138Syongari			/* highaddr	*/ BUS_SPACE_MAXADDR,
1344165138Syongari			/* filter	*/ NULL,
1345165138Syongari			/* filterarg	*/ NULL,
1346165138Syongari			/* maxsize	*/ MAXPHYS,
1347165138Syongari			/* nsegments	*/ max_sg,
1348165138Syongari			/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
1349165138Syongari			/* flags	*/ BUS_DMA_ALLOCNOW,
1350165138Syongari			&adv->buffer_dmat) != 0) {
1351165138Syongari		return (ENXIO);
1352165138Syongari	}
1353165138Syongari	adv->init_level++;
1354165138Syongari
1355165138Syongari	/* DMA tag for our sense buffers */
1356165138Syongari	if (bus_dma_tag_create(
1357165138Syongari			/* parent	*/ adv->parent_dmat,
1358165138Syongari			/* alignment	*/ 1,
1359165138Syongari			/* boundary	*/ 0,
1360165138Syongari			/* lowaddr	*/ BUS_SPACE_MAXADDR,
1361165138Syongari			/* highaddr	*/ BUS_SPACE_MAXADDR,
1362165138Syongari			/* filter	*/ NULL,
1363165138Syongari			/* filterarg	*/ NULL,
1364165138Syongari			/* maxsize	*/ sizeof(struct scsi_sense_data) *
1365165138Syongari					   adv->max_openings,
1366165138Syongari			/* nsegments	*/ 1,
1367165138Syongari			/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
1368165138Syongari			/* flags	*/ 0,
1369165138Syongari			&adv->sense_dmat) != 0) {
1370165138Syongari		return (ENXIO);
1371165138Syongari        }
1372165138Syongari
1373165138Syongari	adv->init_level++;
1374165138Syongari
1375165138Syongari	/* Allocation for our sense buffers */
1376165138Syongari	if (bus_dmamem_alloc(adv->sense_dmat, (void **)&adv->sense_buffers,
1377165138Syongari			     BUS_DMA_NOWAIT, &adv->sense_dmamap) != 0) {
1378165138Syongari		return (ENOMEM);
1379165138Syongari	}
1380165138Syongari
1381165138Syongari	adv->init_level++;
1382165138Syongari
1383165138Syongari	/* And permanently map them */
1384165138Syongari	bus_dmamap_load(adv->sense_dmat, adv->sense_dmamap,
1385165138Syongari       			adv->sense_buffers,
1386165138Syongari			sizeof(struct scsi_sense_data)*adv->max_openings,
1387165138Syongari			adv_map, &adv->sense_physbase, /*flags*/0);
1388165138Syongari
1389165138Syongari	adv->init_level++;
1390165138Syongari
1391165138Syongari	/*
1392165138Syongari	 * Fire up the chip
1393165138Syongari	 */
1394165138Syongari	if (adv_start_chip(adv) != 1) {
1395165138Syongari		printf("adv%d: Unable to start on board processor. Aborting.\n",
1396165138Syongari		       adv->unit);
1397165138Syongari		return (ENXIO);
1398165138Syongari	}
1399165138Syongari
1400165138Syongari	/*
1401165138Syongari	 * Create the device queue for our SIM.
1402165138Syongari	 */
1403165138Syongari	devq = cam_simq_alloc(adv->max_openings);
1404165138Syongari	if (devq == NULL)
1405165138Syongari		return (ENOMEM);
1406165138Syongari
1407165138Syongari	/*
1408165138Syongari	 * Construct our SIM entry.
1409165138Syongari	 */
1410165138Syongari	adv->sim = cam_sim_alloc(adv_action, adv_poll, "adv", adv, adv->unit,
1411165138Syongari				 1, adv->max_openings, devq);
1412165138Syongari	if (adv->sim == NULL)
1413165138Syongari		return (ENOMEM);
1414165138Syongari
1415165138Syongari	/*
1416165138Syongari	 * Register the bus.
1417165138Syongari	 *
1418165138Syongari	 * XXX Twin Channel EISA Cards???
1419165138Syongari	 */
1420165138Syongari	if (xpt_bus_register(adv->sim, 0) != CAM_SUCCESS) {
1421165138Syongari		cam_sim_free(adv->sim, /*free devq*/TRUE);
1422165138Syongari		return (ENXIO);
1423165138Syongari	}
1424165138Syongari
1425165138Syongari	if (xpt_create_path(&adv->path, /*periph*/NULL, cam_sim_path(adv->sim),
1426165138Syongari			    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD)
1427165138Syongari	    != CAM_REQ_CMP) {
1428165138Syongari		xpt_bus_deregister(cam_sim_path(adv->sim));
1429165138Syongari		cam_sim_free(adv->sim, /*free devq*/TRUE);
1430165138Syongari		return (ENXIO);
1431165138Syongari	}
1432165138Syongari
1433165138Syongari	xpt_setup_ccb(&csa.ccb_h, adv->path, /*priority*/5);
1434165138Syongari	csa.ccb_h.func_code = XPT_SASYNC_CB;
1435165138Syongari	csa.event_enable = AC_FOUND_DEVICE|AC_LOST_DEVICE;
1436165138Syongari	csa.callback = advasync;
1437165138Syongari	csa.callback_arg = adv;
1438165138Syongari	xpt_action((union ccb *)&csa);
1439165138Syongari	return (0);
1440165138Syongari}
1441165138Syongari