1139749Simp/*-
239217Sgibbs * Generic driver for the Advanced Systems Inc. SCSI controllers
339217Sgibbs * Product specific probe and attach routines can be found in:
439217Sgibbs *
539217Sgibbs * i386/isa/adv_isa.c	ABP5140, ABP542, ABP5150, ABP842, ABP852
639217Sgibbs * i386/eisa/adv_eisa.c	ABP742, ABP752
739217Sgibbs * pci/adv_pci.c	ABP920, ABP930, ABP930U, ABP930UA, ABP940, ABP940U,
839217Sgibbs *			ABP940UA, ABP950, ABP960, ABP960U, ABP960UA,
939217Sgibbs *			ABP970, ABP970U
1039217Sgibbs *
1155945Sgibbs * Copyright (c) 1996-2000 Justin Gibbs.
1239217Sgibbs * All rights reserved.
1339217Sgibbs *
1439217Sgibbs * Redistribution and use in source and binary forms, with or without
1539217Sgibbs * modification, are permitted provided that the following conditions
1639217Sgibbs * are met:
1739217Sgibbs * 1. Redistributions of source code must retain the above copyright
1839217Sgibbs *    notice, this list of conditions, and the following disclaimer,
1939217Sgibbs *    without modification, immediately at the beginning of the file.
2039217Sgibbs * 2. The name of the author may not be used to endorse or promote products
2139217Sgibbs *    derived from this software without specific prior written permission.
2239217Sgibbs *
2339217Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2439217Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2539217Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2639217Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2739217Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2839217Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2939217Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3039217Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3139217Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3239217Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3339217Sgibbs * SUCH DAMAGE.
3439217Sgibbs */
35139749Simp/*-
3639217Sgibbs * Ported from:
3739217Sgibbs * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
3839217Sgibbs *
3939217Sgibbs * Copyright (c) 1995-1997 Advanced System Products, Inc.
4039217Sgibbs * All Rights Reserved.
4139217Sgibbs *
4239217Sgibbs * Redistribution and use in source and binary forms, with or without
4339217Sgibbs * modification, are permitted provided that redistributions of source
4439217Sgibbs * code retain the above copyright notice and this comment without
4539217Sgibbs * modification.
4639217Sgibbs */
47119418Sobrien
48119418Sobrien#include <sys/cdefs.h>
49119418Sobrien__FBSDID("$FreeBSD: stable/11/sys/dev/advansys/advansys.c 315812 2017-03-23 06:40:20Z mav $");
5039217Sgibbs
5139217Sgibbs#include <sys/param.h>
52241492Sjhb#include <sys/conf.h>
5339217Sgibbs#include <sys/systm.h>
5439217Sgibbs#include <sys/malloc.h>
5539217Sgibbs#include <sys/kernel.h>
56117126Sscottl#include <sys/lock.h>
57165102Smjacob#include <sys/module.h>
58117126Sscottl#include <sys/mutex.h>
5939217Sgibbs
6039217Sgibbs#include <machine/bus.h>
6159082Snyan#include <machine/resource.h>
6259082Snyan#include <sys/bus.h>
6359082Snyan#include <sys/rman.h>
6439217Sgibbs
6539217Sgibbs#include <cam/cam.h>
6639217Sgibbs#include <cam/cam_ccb.h>
6739217Sgibbs#include <cam/cam_sim.h>
6839217Sgibbs#include <cam/cam_xpt_sim.h>
6939217Sgibbs#include <cam/cam_debug.h>
7039217Sgibbs
7139217Sgibbs#include <cam/scsi/scsi_all.h>
7239217Sgibbs#include <cam/scsi/scsi_message.h>
7339217Sgibbs
7439217Sgibbs#include <vm/vm.h>
7539217Sgibbs#include <vm/vm_param.h>
7639217Sgibbs#include <vm/pmap.h>
7739217Sgibbs
7839217Sgibbs#include <dev/advansys/advansys.h>
7939217Sgibbs
8039217Sgibbsstatic void	adv_action(struct cam_sim *sim, union ccb *ccb);
8139217Sgibbsstatic void	adv_execute_ccb(void *arg, bus_dma_segment_t *dm_segs,
8239217Sgibbs				int nsegments, int error);
83241492Sjhbstatic void	adv_intr_locked(struct adv_softc *adv);
8439217Sgibbsstatic void	adv_poll(struct cam_sim *sim);
8539217Sgibbsstatic void	adv_run_doneq(struct adv_softc *adv);
8639217Sgibbsstatic struct adv_ccb_info *
8739217Sgibbs		adv_alloc_ccb_info(struct adv_softc *adv);
8839217Sgibbsstatic void	adv_destroy_ccb_info(struct adv_softc *adv,
8940420Sgibbs				     struct adv_ccb_info *cinfo);
9039217Sgibbsstatic __inline struct adv_ccb_info *
9139217Sgibbs		adv_get_ccb_info(struct adv_softc *adv);
9239217Sgibbsstatic __inline void adv_free_ccb_info(struct adv_softc *adv,
9339217Sgibbs				       struct adv_ccb_info *cinfo);
9455945Sgibbsstatic __inline void adv_set_state(struct adv_softc *adv, adv_state state);
9555945Sgibbsstatic __inline void adv_clear_state(struct adv_softc *adv, union ccb* ccb);
9655945Sgibbsstatic void adv_clear_state_really(struct adv_softc *adv, union ccb* ccb);
9739217Sgibbs
9839217Sgibbsstatic __inline struct adv_ccb_info *
9939217Sgibbsadv_get_ccb_info(struct adv_softc *adv)
10039217Sgibbs{
10139217Sgibbs	struct adv_ccb_info *cinfo;
10239217Sgibbs
103241492Sjhb	if (!dumping)
104241492Sjhb		mtx_assert(&adv->lock, MA_OWNED);
10539217Sgibbs	if ((cinfo = SLIST_FIRST(&adv->free_ccb_infos)) != NULL) {
10639217Sgibbs		SLIST_REMOVE_HEAD(&adv->free_ccb_infos, links);
10739217Sgibbs	} else {
10839217Sgibbs		cinfo = adv_alloc_ccb_info(adv);
10939217Sgibbs	}
11039217Sgibbs
11139217Sgibbs	return (cinfo);
11239217Sgibbs}
11339217Sgibbs
11439217Sgibbsstatic __inline void
11539217Sgibbsadv_free_ccb_info(struct adv_softc *adv, struct adv_ccb_info *cinfo)
11639217Sgibbs{
11739217Sgibbs
118241492Sjhb	if (!dumping)
119241492Sjhb		mtx_assert(&adv->lock, MA_OWNED);
12039217Sgibbs	cinfo->state = ACCB_FREE;
12139217Sgibbs	SLIST_INSERT_HEAD(&adv->free_ccb_infos, cinfo, links);
12239217Sgibbs}
12339217Sgibbs
12455945Sgibbsstatic __inline void
12555945Sgibbsadv_set_state(struct adv_softc *adv, adv_state state)
12655945Sgibbs{
12755945Sgibbs	if (adv->state == 0)
12855945Sgibbs		xpt_freeze_simq(adv->sim, /*count*/1);
12955945Sgibbs	adv->state |= state;
13055945Sgibbs}
13155945Sgibbs
13255945Sgibbsstatic __inline void
13355945Sgibbsadv_clear_state(struct adv_softc *adv, union ccb* ccb)
13455945Sgibbs{
13555945Sgibbs	if (adv->state != 0)
13655945Sgibbs		adv_clear_state_really(adv, ccb);
13755945Sgibbs}
13855945Sgibbs
13955945Sgibbsstatic void
14055945Sgibbsadv_clear_state_really(struct adv_softc *adv, union ccb* ccb)
14155945Sgibbs{
142241492Sjhb
143241492Sjhb	if (!dumping)
144241492Sjhb		mtx_assert(&adv->lock, MA_OWNED);
14555945Sgibbs	if ((adv->state & ADV_BUSDMA_BLOCK_CLEARED) != 0)
14655945Sgibbs		adv->state &= ~(ADV_BUSDMA_BLOCK_CLEARED|ADV_BUSDMA_BLOCK);
14755945Sgibbs	if ((adv->state & ADV_RESOURCE_SHORTAGE) != 0) {
14855945Sgibbs		int openings;
14955945Sgibbs
15055945Sgibbs		openings = adv->max_openings - adv->cur_active - ADV_MIN_FREE_Q;
15155945Sgibbs		if (openings >= adv->openings_needed) {
15255945Sgibbs			adv->state &= ~ADV_RESOURCE_SHORTAGE;
15355945Sgibbs			adv->openings_needed = 0;
15455945Sgibbs		}
15555945Sgibbs	}
15655945Sgibbs
15755945Sgibbs	if ((adv->state & ADV_IN_TIMEOUT) != 0) {
15855945Sgibbs		struct adv_ccb_info *cinfo;
15955945Sgibbs
16055945Sgibbs		cinfo = (struct adv_ccb_info *)ccb->ccb_h.ccb_cinfo_ptr;
16155945Sgibbs		if ((cinfo->state & ACCB_RECOVERY_CCB) != 0) {
16255945Sgibbs			struct ccb_hdr *ccb_h;
16355945Sgibbs
16455945Sgibbs			/*
16555945Sgibbs			 * We now traverse our list of pending CCBs
16655945Sgibbs			 * and reinstate their timeouts.
16755945Sgibbs			 */
16855945Sgibbs			ccb_h = LIST_FIRST(&adv->pending_ccbs);
16955945Sgibbs			while (ccb_h != NULL) {
170241492Sjhb				cinfo = ccb_h->ccb_cinfo_ptr;
171274819Ssmh				callout_reset_sbt(&cinfo->timer,
172274819Ssmh				    SBT_1MS * ccb_h->timeout, 0,
173274819Ssmh				    adv_timeout, ccb_h, 0);
17455945Sgibbs				ccb_h = LIST_NEXT(ccb_h, sim_links.le);
17555945Sgibbs			}
17655945Sgibbs			adv->state &= ~ADV_IN_TIMEOUT;
177241492Sjhb			device_printf(adv->dev, "No longer in timeout\n");
17855945Sgibbs		}
17955945Sgibbs	}
18055945Sgibbs	if (adv->state == 0)
18155945Sgibbs		ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
18255945Sgibbs}
18355945Sgibbs
18439217Sgibbsvoid
18539217Sgibbsadv_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
18639217Sgibbs{
18739217Sgibbs	bus_addr_t* physaddr;
18839217Sgibbs
18939217Sgibbs	physaddr = (bus_addr_t*)arg;
19039217Sgibbs	*physaddr = segs->ds_addr;
19139217Sgibbs}
19239217Sgibbs
19339217Sgibbsstatic void
19439217Sgibbsadv_action(struct cam_sim *sim, union ccb *ccb)
19539217Sgibbs{
19639217Sgibbs	struct adv_softc *adv;
19739217Sgibbs
19839217Sgibbs	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("adv_action\n"));
19939217Sgibbs
20039217Sgibbs	adv = (struct adv_softc *)cam_sim_softc(sim);
201241492Sjhb	mtx_assert(&adv->lock, MA_OWNED);
20239217Sgibbs
20339217Sgibbs	switch (ccb->ccb_h.func_code) {
20439217Sgibbs	/* Common cases first */
20539217Sgibbs	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
20639217Sgibbs	{
20739217Sgibbs		struct	ccb_hdr *ccb_h;
20839217Sgibbs		struct	ccb_scsiio *csio;
20939217Sgibbs		struct	adv_ccb_info *cinfo;
210246713Skib		int error;
21139217Sgibbs
21239217Sgibbs		ccb_h = &ccb->ccb_h;
21339217Sgibbs		csio = &ccb->csio;
21439217Sgibbs		cinfo = adv_get_ccb_info(adv);
21539217Sgibbs		if (cinfo == NULL)
21639217Sgibbs			panic("XXX Handle CCB info error!!!");
21739217Sgibbs
21839217Sgibbs		ccb_h->ccb_cinfo_ptr = cinfo;
21955945Sgibbs		cinfo->ccb = ccb;
22039217Sgibbs
221246713Skib		error = bus_dmamap_load_ccb(adv->buffer_dmat,
222246713Skib					    cinfo->dmamap,
223246713Skib					    ccb,
224246713Skib					    adv_execute_ccb,
225246713Skib					    csio, /*flags*/0);
226246713Skib		if (error == EINPROGRESS) {
227246713Skib			/*
228246713Skib			 * So as to maintain ordering, freeze the controller
229246713Skib			 * queue until our mapping is returned.
230246713Skib			 */
231246713Skib			adv_set_state(adv, ADV_BUSDMA_BLOCK);
23239217Sgibbs		}
23339217Sgibbs		break;
23439217Sgibbs	}
23539217Sgibbs	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
23639217Sgibbs	case XPT_ABORT:			/* Abort the specified CCB */
23739217Sgibbs		/* XXX Implement */
23839217Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
23939217Sgibbs		xpt_done(ccb);
24039217Sgibbs		break;
241163816Smjacob#define	IS_CURRENT_SETTINGS(c)	(c->type == CTS_TYPE_CURRENT_SETTINGS)
242163816Smjacob#define	IS_USER_SETTINGS(c)	(c->type == CTS_TYPE_USER_SETTINGS)
24339217Sgibbs	case XPT_SET_TRAN_SETTINGS:
24439217Sgibbs	{
245163816Smjacob		struct ccb_trans_settings_scsi *scsi;
246163816Smjacob		struct ccb_trans_settings_spi *spi;
24739217Sgibbs		struct	 ccb_trans_settings *cts;
24839217Sgibbs		target_bit_vector targ_mask;
24946581Sken		struct adv_transinfo *tconf;
25039217Sgibbs		u_int	 update_type;
25139217Sgibbs
25239217Sgibbs		cts = &ccb->cts;
25339217Sgibbs		targ_mask = ADV_TID_TO_TARGET_MASK(cts->ccb_h.target_id);
25439217Sgibbs		update_type = 0;
25546581Sken
25646581Sken		/*
25746581Sken		 * The user must specify which type of settings he wishes
25846581Sken		 * to change.
25946581Sken		 */
260163816Smjacob		if (IS_CURRENT_SETTINGS(cts) && !IS_USER_SETTINGS(cts)) {
26146581Sken			tconf = &adv->tinfo[cts->ccb_h.target_id].current;
26239217Sgibbs			update_type |= ADV_TRANS_GOAL;
263163816Smjacob		} else if (IS_USER_SETTINGS(cts) && !IS_CURRENT_SETTINGS(cts)) {
26446581Sken			tconf = &adv->tinfo[cts->ccb_h.target_id].user;
26539217Sgibbs			update_type |= ADV_TRANS_USER;
26646581Sken		} else {
26746581Sken			ccb->ccb_h.status = CAM_REQ_INVALID;
26846581Sken			break;
26946581Sken		}
27039217Sgibbs
271163816Smjacob		scsi = &cts->proto_specific.scsi;
272163816Smjacob		spi = &cts->xport_specific.spi;
273163816Smjacob		if ((update_type & ADV_TRANS_GOAL) != 0) {
274163816Smjacob			if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
275163816Smjacob				if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0)
276163816Smjacob					adv->disc_enable |= targ_mask;
277163816Smjacob				else
278163816Smjacob					adv->disc_enable &= ~targ_mask;
279163816Smjacob				adv_write_lram_8(adv, ADVV_DISC_ENABLE_B,
280163816Smjacob						 adv->disc_enable);
281163816Smjacob			}
28239217Sgibbs
283163816Smjacob			if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
284163816Smjacob				if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0)
285163816Smjacob					adv->cmd_qng_enabled |= targ_mask;
286163816Smjacob				else
287163816Smjacob					adv->cmd_qng_enabled &= ~targ_mask;
288163816Smjacob			}
289163816Smjacob		}
290163816Smjacob
291163816Smjacob		if ((update_type & ADV_TRANS_USER) != 0) {
292163816Smjacob			if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
293163816Smjacob				if ((spi->flags & CTS_SPI_VALID_DISC) != 0)
294163816Smjacob					adv->user_disc_enable |= targ_mask;
295163816Smjacob				else
296163816Smjacob					adv->user_disc_enable &= ~targ_mask;
297163816Smjacob			}
298163816Smjacob
299163816Smjacob			if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
300163816Smjacob				if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0)
301163816Smjacob					adv->user_cmd_qng_enabled |= targ_mask;
302163816Smjacob				else
303163816Smjacob					adv->user_cmd_qng_enabled &= ~targ_mask;
304163816Smjacob			}
305163816Smjacob		}
306163816Smjacob
307163816Smjacob		/*
308163816Smjacob		 * If the user specifies either the sync rate, or offset,
309163816Smjacob		 * but not both, the unspecified parameter defaults to its
310163816Smjacob		 * current value in transfer negotiations.
311163816Smjacob		 */
312163816Smjacob		if (((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0)
313163816Smjacob		 || ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)) {
314163816Smjacob			/*
315163816Smjacob			 * If the user provided a sync rate but no offset,
316163816Smjacob			 * use the current offset.
317163816Smjacob			 */
318163816Smjacob			if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0)
319163816Smjacob				spi->sync_offset = tconf->offset;
320163816Smjacob
321163816Smjacob			/*
322163816Smjacob			 * If the user provided an offset but no sync rate,
323163816Smjacob			 * use the current sync rate.
324163816Smjacob			 */
325163816Smjacob			if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0)
326163816Smjacob				spi->sync_period = tconf->period;
327163816Smjacob
328163816Smjacob			adv_period_offset_to_sdtr(adv, &spi->sync_period,
329163816Smjacob						  &spi->sync_offset,
330163816Smjacob						  cts->ccb_h.target_id);
331163816Smjacob
332163816Smjacob			adv_set_syncrate(adv, /*struct cam_path */NULL,
333163816Smjacob					 cts->ccb_h.target_id, spi->sync_period,
334163816Smjacob					 spi->sync_offset, update_type);
335163816Smjacob		}
33639217Sgibbs
33739217Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
33839217Sgibbs		xpt_done(ccb);
33939217Sgibbs		break;
34039217Sgibbs	}
34139217Sgibbs	case XPT_GET_TRAN_SETTINGS:
34239217Sgibbs	/* Get default/user set transfer settings for the target */
34339217Sgibbs	{
344163816Smjacob		struct ccb_trans_settings_scsi *scsi;
345163816Smjacob		struct ccb_trans_settings_spi *spi;
34639217Sgibbs		struct ccb_trans_settings *cts;
34739217Sgibbs		struct adv_transinfo *tconf;
34839217Sgibbs		target_bit_vector target_mask;
34939217Sgibbs
35039217Sgibbs		cts = &ccb->cts;
35139217Sgibbs		target_mask = ADV_TID_TO_TARGET_MASK(cts->ccb_h.target_id);
35239217Sgibbs
353163816Smjacob		scsi = &cts->proto_specific.scsi;
354163816Smjacob		spi = &cts->xport_specific.spi;
35539217Sgibbs
356163816Smjacob		cts->protocol = PROTO_SCSI;
357163816Smjacob		cts->protocol_version = SCSI_REV_2;
358163816Smjacob		cts->transport = XPORT_SPI;
359163816Smjacob		cts->transport_version = 2;
360163816Smjacob
361163816Smjacob		scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
362163816Smjacob		spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
363163816Smjacob
364163816Smjacob		if (cts->type == CTS_TYPE_CURRENT_SETTINGS) {
365163816Smjacob			tconf = &adv->tinfo[cts->ccb_h.target_id].current;
366163816Smjacob			if ((adv->disc_enable & target_mask) != 0)
367163816Smjacob				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
368163816Smjacob			if ((adv->cmd_qng_enabled & target_mask) != 0)
369163816Smjacob				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
370163816Smjacob		} else {
371163816Smjacob			tconf = &adv->tinfo[cts->ccb_h.target_id].user;
372163816Smjacob			if ((adv->user_disc_enable & target_mask) != 0)
373163816Smjacob				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
374163816Smjacob			if ((adv->user_cmd_qng_enabled & target_mask) != 0)
375163816Smjacob				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
376163816Smjacob		}
377163816Smjacob		spi->sync_period = tconf->period;
378163816Smjacob		spi->sync_offset = tconf->offset;
379163816Smjacob		spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
380163816Smjacob		spi->valid = CTS_SPI_VALID_SYNC_RATE
381163816Smjacob			   | CTS_SPI_VALID_SYNC_OFFSET
382163816Smjacob			   | CTS_SPI_VALID_BUS_WIDTH
383163816Smjacob			   | CTS_SPI_VALID_DISC;
384163816Smjacob		scsi->valid = CTS_SCSI_VALID_TQ;
38539217Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
38639217Sgibbs		xpt_done(ccb);
38739217Sgibbs		break;
38839217Sgibbs	}
38939217Sgibbs	case XPT_CALC_GEOMETRY:
39039217Sgibbs	{
39139217Sgibbs		int	  extended;
39239217Sgibbs
39339217Sgibbs		extended = (adv->control & ADV_CNTL_BIOS_GT_1GB) != 0;
394116351Snjl		cam_calc_geometry(&ccb->ccg, extended);
39539217Sgibbs		xpt_done(ccb);
39639217Sgibbs		break;
39739217Sgibbs	}
39839217Sgibbs	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
39939217Sgibbs	{
40039217Sgibbs
40139217Sgibbs		adv_stop_execution(adv);
40255945Sgibbs		adv_reset_bus(adv, /*initiate_reset*/TRUE);
40339217Sgibbs		adv_start_execution(adv);
40439217Sgibbs
40539217Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
40639217Sgibbs		xpt_done(ccb);
40739217Sgibbs		break;
40839217Sgibbs	}
40939217Sgibbs	case XPT_TERM_IO:		/* Terminate the I/O process */
41039217Sgibbs		/* XXX Implement */
41139217Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
41239217Sgibbs		xpt_done(ccb);
41339217Sgibbs		break;
41439217Sgibbs	case XPT_PATH_INQ:		/* Path routing inquiry */
41539217Sgibbs	{
41639217Sgibbs		struct ccb_pathinq *cpi = &ccb->cpi;
41739217Sgibbs
41839217Sgibbs		cpi->version_num = 1; /* XXX??? */
41939217Sgibbs		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE;
42039217Sgibbs		cpi->target_sprt = 0;
42139217Sgibbs		cpi->hba_misc = 0;
42239217Sgibbs		cpi->hba_eng_cnt = 0;
42339217Sgibbs		cpi->max_target = 7;
42439217Sgibbs		cpi->max_lun = 7;
42539217Sgibbs		cpi->initiator_id = adv->scsi_id;
42639217Sgibbs		cpi->bus_id = cam_sim_bus(sim);
42746581Sken		cpi->base_transfer_speed = 3300;
428315812Smav		strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
429315812Smav		strlcpy(cpi->hba_vid, "Advansys", HBA_IDLEN);
430315812Smav		strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
43139217Sgibbs		cpi->unit_number = cam_sim_unit(sim);
43239217Sgibbs		cpi->ccb_h.status = CAM_REQ_CMP;
433163816Smjacob                cpi->transport = XPORT_SPI;
434163816Smjacob                cpi->transport_version = 2;
435163816Smjacob                cpi->protocol = PROTO_SCSI;
436163816Smjacob                cpi->protocol_version = SCSI_REV_2;
43739217Sgibbs		xpt_done(ccb);
43839217Sgibbs		break;
43939217Sgibbs	}
44039217Sgibbs	default:
44139217Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
44239217Sgibbs		xpt_done(ccb);
44339217Sgibbs		break;
44439217Sgibbs	}
44539217Sgibbs}
44639217Sgibbs
44739217Sgibbs/*
44839217Sgibbs * Currently, the output of bus_dmammap_load suits our needs just
44939217Sgibbs * fine, but should it change, we'd need to do something here.
45039217Sgibbs */
45139217Sgibbs#define adv_fixup_dmasegs(adv, dm_segs) (struct adv_sg_entry *)(dm_segs)
45239217Sgibbs
45339217Sgibbsstatic void
45439217Sgibbsadv_execute_ccb(void *arg, bus_dma_segment_t *dm_segs,
45539217Sgibbs		int nsegments, int error)
45639217Sgibbs{
45739217Sgibbs	struct	ccb_scsiio *csio;
45839217Sgibbs	struct	ccb_hdr *ccb_h;
45939217Sgibbs	struct	cam_sim *sim;
46039217Sgibbs        struct	adv_softc *adv;
46139217Sgibbs	struct	adv_ccb_info *cinfo;
46239217Sgibbs	struct	adv_scsi_q scsiq;
46339217Sgibbs	struct	adv_sg_head sghead;
46439217Sgibbs
46539217Sgibbs	csio = (struct ccb_scsiio *)arg;
46639217Sgibbs	ccb_h = &csio->ccb_h;
46739217Sgibbs	sim = xpt_path_sim(ccb_h->path);
46839217Sgibbs	adv = (struct adv_softc *)cam_sim_softc(sim);
46939217Sgibbs	cinfo = (struct adv_ccb_info *)csio->ccb_h.ccb_cinfo_ptr;
470241492Sjhb	if (!dumping)
471241492Sjhb		mtx_assert(&adv->lock, MA_OWNED);
47239217Sgibbs
47355945Sgibbs	/*
47455945Sgibbs	 * Setup our done routine to release the simq on
47555945Sgibbs	 * the next ccb that completes.
47655945Sgibbs	 */
47755945Sgibbs	if ((adv->state & ADV_BUSDMA_BLOCK) != 0)
47855945Sgibbs		adv->state |= ADV_BUSDMA_BLOCK_CLEARED;
47955945Sgibbs
48039217Sgibbs	if ((ccb_h->flags & CAM_CDB_POINTER) != 0) {
48139217Sgibbs		if ((ccb_h->flags & CAM_CDB_PHYS) == 0) {
48239217Sgibbs			/* XXX Need phystovirt!!!! */
48339217Sgibbs			/* How about pmap_kenter??? */
48439217Sgibbs			scsiq.cdbptr = csio->cdb_io.cdb_ptr;
48539217Sgibbs		} else {
48639217Sgibbs			scsiq.cdbptr = csio->cdb_io.cdb_ptr;
48739217Sgibbs		}
48839217Sgibbs	} else {
48939217Sgibbs		scsiq.cdbptr = csio->cdb_io.cdb_bytes;
49039217Sgibbs	}
49139217Sgibbs	/*
49239217Sgibbs	 * Build up the request
49339217Sgibbs	 */
49439217Sgibbs	scsiq.q1.status = 0;
49539217Sgibbs	scsiq.q1.q_no = 0;
49639217Sgibbs	scsiq.q1.cntl = 0;
49739217Sgibbs	scsiq.q1.sg_queue_cnt = 0;
49839217Sgibbs	scsiq.q1.target_id = ADV_TID_TO_TARGET_MASK(ccb_h->target_id);
49939217Sgibbs	scsiq.q1.target_lun = ccb_h->target_lun;
50039217Sgibbs	scsiq.q1.sense_len = csio->sense_len;
50139217Sgibbs	scsiq.q1.extra_bytes = 0;
50255945Sgibbs	scsiq.q2.ccb_index = cinfo - adv->ccb_infos;
50339217Sgibbs	scsiq.q2.target_ix = ADV_TIDLUN_TO_IX(ccb_h->target_id,
50439217Sgibbs					      ccb_h->target_lun);
50539217Sgibbs	scsiq.q2.flag = 0;
50639217Sgibbs	scsiq.q2.cdb_len = csio->cdb_len;
50739217Sgibbs	if ((ccb_h->flags & CAM_TAG_ACTION_VALID) != 0)
50839217Sgibbs		scsiq.q2.tag_code = csio->tag_action;
50939217Sgibbs	else
51039217Sgibbs		scsiq.q2.tag_code = 0;
51139217Sgibbs	scsiq.q2.vm_id = 0;
51239217Sgibbs
51339217Sgibbs	if (nsegments != 0) {
514115343Sscottl		bus_dmasync_op_t op;
51539217Sgibbs
51639217Sgibbs		scsiq.q1.data_addr = dm_segs->ds_addr;
51739217Sgibbs                scsiq.q1.data_cnt = dm_segs->ds_len;
51839217Sgibbs		if (nsegments > 1) {
51939217Sgibbs			scsiq.q1.cntl |= QC_SG_HEAD;
52039217Sgibbs			sghead.entry_cnt
52139217Sgibbs			    = sghead.entry_to_copy
52239217Sgibbs			    = nsegments;
52339217Sgibbs			sghead.res = 0;
52439217Sgibbs			sghead.sg_list = adv_fixup_dmasegs(adv, dm_segs);
52539217Sgibbs			scsiq.sg_head = &sghead;
52639217Sgibbs		} else {
52739217Sgibbs			scsiq.sg_head = NULL;
52839217Sgibbs		}
52939217Sgibbs		if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN)
53039217Sgibbs			op = BUS_DMASYNC_PREREAD;
53139217Sgibbs		else
53239217Sgibbs			op = BUS_DMASYNC_PREWRITE;
53339217Sgibbs		bus_dmamap_sync(adv->buffer_dmat, cinfo->dmamap, op);
53439217Sgibbs	} else {
53539217Sgibbs		scsiq.q1.data_addr = 0;
53639217Sgibbs		scsiq.q1.data_cnt = 0;
53739217Sgibbs		scsiq.sg_head = NULL;
53839217Sgibbs	}
53939217Sgibbs
54040027Sgibbs	/*
54140027Sgibbs	 * Last time we need to check if this SCB needs to
54240027Sgibbs	 * be aborted.
54340027Sgibbs	 */
54440027Sgibbs	if (ccb_h->status != CAM_REQ_INPROG) {
54555945Sgibbs		if (nsegments != 0)
54640027Sgibbs			bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap);
54755945Sgibbs		adv_clear_state(adv, (union ccb *)csio);
54840027Sgibbs		adv_free_ccb_info(adv, cinfo);
54940027Sgibbs		xpt_done((union ccb *)csio);
55040027Sgibbs		return;
55140027Sgibbs	}
55240027Sgibbs
55339217Sgibbs	if (adv_execute_scsi_queue(adv, &scsiq, csio->dxfer_len) != 0) {
55439217Sgibbs		/* Temporary resource shortage */
55555945Sgibbs		adv_set_state(adv, ADV_RESOURCE_SHORTAGE);
55655945Sgibbs		if (nsegments != 0)
55739217Sgibbs			bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap);
55855945Sgibbs		csio->ccb_h.status = CAM_REQUEUE_REQ;
55955945Sgibbs		adv_clear_state(adv, (union ccb *)csio);
56039217Sgibbs		adv_free_ccb_info(adv, cinfo);
56139217Sgibbs		xpt_done((union ccb *)csio);
56239217Sgibbs		return;
56339217Sgibbs	}
56440027Sgibbs	cinfo->state |= ACCB_ACTIVE;
56539217Sgibbs	ccb_h->status |= CAM_SIM_QUEUED;
56639217Sgibbs	LIST_INSERT_HEAD(&adv->pending_ccbs, ccb_h, sim_links.le);
56739217Sgibbs	/* Schedule our timeout */
568274819Ssmh	callout_reset_sbt(&cinfo->timer, SBT_1MS * ccb_h->timeout, 0,
569274819Ssmh	    adv_timeout, csio, 0);
57039217Sgibbs}
57139217Sgibbs
57239217Sgibbsstatic struct adv_ccb_info *
57339217Sgibbsadv_alloc_ccb_info(struct adv_softc *adv)
57439217Sgibbs{
57539217Sgibbs	int error;
57639217Sgibbs	struct adv_ccb_info *cinfo;
57739217Sgibbs
57855945Sgibbs	cinfo = &adv->ccb_infos[adv->ccb_infos_allocated];
57939217Sgibbs	cinfo->state = ACCB_FREE;
580241492Sjhb	callout_init_mtx(&cinfo->timer, &adv->lock, 0);
58139217Sgibbs	error = bus_dmamap_create(adv->buffer_dmat, /*flags*/0,
58239217Sgibbs				  &cinfo->dmamap);
58339217Sgibbs	if (error != 0) {
584241492Sjhb		device_printf(adv->dev, "Unable to allocate CCB info "
585241492Sjhb		    "dmamap - error %d\n", error);
58655945Sgibbs		return (NULL);
58739217Sgibbs	}
58855945Sgibbs	adv->ccb_infos_allocated++;
58939217Sgibbs	return (cinfo);
59039217Sgibbs}
59139217Sgibbs
59239217Sgibbsstatic void
59339217Sgibbsadv_destroy_ccb_info(struct adv_softc *adv, struct adv_ccb_info *cinfo)
59439217Sgibbs{
595241492Sjhb
596241492Sjhb	callout_drain(&cinfo->timer);
59739217Sgibbs	bus_dmamap_destroy(adv->buffer_dmat, cinfo->dmamap);
59839217Sgibbs}
59939217Sgibbs
60039217Sgibbsvoid
60139217Sgibbsadv_timeout(void *arg)
60239217Sgibbs{
60339217Sgibbs	union ccb *ccb;
60439217Sgibbs	struct adv_softc *adv;
605241492Sjhb	struct adv_ccb_info *cinfo, *cinfo2;
60639217Sgibbs
60739217Sgibbs	ccb = (union ccb *)arg;
60839217Sgibbs	adv = (struct adv_softc *)xpt_path_sim(ccb->ccb_h.path)->softc;
60939217Sgibbs	cinfo = (struct adv_ccb_info *)ccb->ccb_h.ccb_cinfo_ptr;
610241492Sjhb	mtx_assert(&adv->lock, MA_OWNED);
61139217Sgibbs
61239217Sgibbs	xpt_print_path(ccb->ccb_h.path);
61339217Sgibbs	printf("Timed out\n");
61439217Sgibbs
61539217Sgibbs	/* Have we been taken care of already?? */
61639217Sgibbs	if (cinfo == NULL || cinfo->state == ACCB_FREE) {
61739217Sgibbs		return;
61839217Sgibbs	}
61939217Sgibbs
62039217Sgibbs	adv_stop_execution(adv);
62139217Sgibbs
62239217Sgibbs	if ((cinfo->state & ACCB_ABORT_QUEUED) == 0) {
62339217Sgibbs		struct ccb_hdr *ccb_h;
62439217Sgibbs
62539217Sgibbs		/*
62639217Sgibbs		 * In order to simplify the recovery process, we ask the XPT
62739217Sgibbs		 * layer to halt the queue of new transactions and we traverse
62839217Sgibbs		 * the list of pending CCBs and remove their timeouts. This
62939217Sgibbs		 * means that the driver attempts to clear only one error
63039217Sgibbs		 * condition at a time.  In general, timeouts that occur
63139217Sgibbs		 * close together are related anyway, so there is no benefit
632298955Spfg		 * in attempting to handle errors in parallel.  Timeouts will
63339217Sgibbs		 * be reinstated when the recovery process ends.
63439217Sgibbs		 */
63555945Sgibbs		adv_set_state(adv, ADV_IN_TIMEOUT);
63639217Sgibbs
63739217Sgibbs		/* This CCB is the CCB representing our recovery actions */
63839217Sgibbs		cinfo->state |= ACCB_RECOVERY_CCB|ACCB_ABORT_QUEUED;
63939217Sgibbs
64039217Sgibbs		ccb_h = LIST_FIRST(&adv->pending_ccbs);
64139217Sgibbs		while (ccb_h != NULL) {
642241492Sjhb			cinfo2 = ccb_h->ccb_cinfo_ptr;
643241492Sjhb			callout_stop(&cinfo2->timer);
64439217Sgibbs			ccb_h = LIST_NEXT(ccb_h, sim_links.le);
64539217Sgibbs		}
64639217Sgibbs
64739217Sgibbs		/* XXX Should send a BDR */
64839217Sgibbs		/* Attempt an abort as our first tact */
64939217Sgibbs		xpt_print_path(ccb->ccb_h.path);
65039217Sgibbs		printf("Attempting abort\n");
65139217Sgibbs		adv_abort_ccb(adv, ccb->ccb_h.target_id,
65239217Sgibbs			      ccb->ccb_h.target_lun, ccb,
65339217Sgibbs			      CAM_CMD_TIMEOUT, /*queued_only*/FALSE);
654241492Sjhb		callout_reset(&cinfo->timer, 2 * hz, adv_timeout, ccb);
65539217Sgibbs	} else {
65639217Sgibbs		/* Our attempt to perform an abort failed, go for a reset */
65739217Sgibbs		xpt_print_path(ccb->ccb_h.path);
65839217Sgibbs		printf("Resetting bus\n");
65939217Sgibbs		ccb->ccb_h.status &= ~CAM_STATUS_MASK;
66039217Sgibbs		ccb->ccb_h.status |= CAM_CMD_TIMEOUT;
66155945Sgibbs		adv_reset_bus(adv, /*initiate_reset*/TRUE);
66239217Sgibbs	}
66339217Sgibbs	adv_start_execution(adv);
66439217Sgibbs}
66539217Sgibbs
66639217Sgibbsstruct adv_softc *
667241492Sjhbadv_alloc(device_t dev, struct resource *res, long offset)
66839217Sgibbs{
66959082Snyan	struct adv_softc *adv = device_get_softc(dev);
67039217Sgibbs
67139217Sgibbs	/*
67239217Sgibbs	 * Allocate a storage area for us
67339217Sgibbs	 */
67439217Sgibbs	LIST_INIT(&adv->pending_ccbs);
67539217Sgibbs	SLIST_INIT(&adv->free_ccb_infos);
67659082Snyan	adv->dev = dev;
677241492Sjhb	adv->res = res;
678241492Sjhb	adv->reg_off = offset;
679241492Sjhb	mtx_init(&adv->lock, "adv", NULL, MTX_DEF);
68039217Sgibbs
68139217Sgibbs	return(adv);
68239217Sgibbs}
68339217Sgibbs
68439217Sgibbsvoid
68539217Sgibbsadv_free(struct adv_softc *adv)
68639217Sgibbs{
68739217Sgibbs	switch (adv->init_level) {
68855945Sgibbs	case 6:
68939217Sgibbs	{
69039217Sgibbs		struct adv_ccb_info *cinfo;
69139217Sgibbs
69239217Sgibbs		while ((cinfo = SLIST_FIRST(&adv->free_ccb_infos)) != NULL) {
69339217Sgibbs			SLIST_REMOVE_HEAD(&adv->free_ccb_infos, links);
69440420Sgibbs			adv_destroy_ccb_info(adv, cinfo);
69539217Sgibbs		}
69639217Sgibbs
69739217Sgibbs		bus_dmamap_unload(adv->sense_dmat, adv->sense_dmamap);
69839217Sgibbs	}
69955945Sgibbs	case 5:
70039217Sgibbs		bus_dmamem_free(adv->sense_dmat, adv->sense_buffers,
70139217Sgibbs                                adv->sense_dmamap);
70255945Sgibbs	case 4:
70355945Sgibbs		bus_dma_tag_destroy(adv->sense_dmat);
70439217Sgibbs	case 3:
70555945Sgibbs		bus_dma_tag_destroy(adv->buffer_dmat);
70639217Sgibbs	case 2:
70755945Sgibbs		bus_dma_tag_destroy(adv->parent_dmat);
70839217Sgibbs	case 1:
70972147Sjhb		if (adv->ccb_infos != NULL)
71072147Sjhb			free(adv->ccb_infos, M_DEVBUF);
71139217Sgibbs	case 0:
712241492Sjhb		mtx_destroy(&adv->lock);
71339217Sgibbs		break;
71439217Sgibbs	}
71539217Sgibbs}
71639217Sgibbs
71739217Sgibbsint
71839217Sgibbsadv_init(struct adv_softc *adv)
71939217Sgibbs{
72039217Sgibbs	struct	  adv_eeprom_config eeprom_config;
72139217Sgibbs	int	  checksum, i;
72255945Sgibbs	int	  max_sync;
72339217Sgibbs	u_int16_t config_lsw;
72439217Sgibbs	u_int16_t config_msw;
72539217Sgibbs
726241492Sjhb	mtx_lock(&adv->lock);
72739217Sgibbs	adv_lib_init(adv);
72839217Sgibbs
72955945Sgibbs  	/*
73055945Sgibbs	 * Stop script execution.
73155945Sgibbs	 */
73255945Sgibbs	adv_write_lram_16(adv, ADV_HALTCODE_W, 0x00FE);
73355945Sgibbs	adv_stop_execution(adv);
73455945Sgibbs	if (adv_stop_chip(adv) == 0 || adv_is_chip_halted(adv) == 0) {
735241492Sjhb		mtx_unlock(&adv->lock);
736241492Sjhb		device_printf(adv->dev,
737241492Sjhb		    "Unable to halt adapter. Initialization failed\n");
73839217Sgibbs		return (1);
73939217Sgibbs	}
74039217Sgibbs	ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR);
74139217Sgibbs	if (ADV_INW(adv, ADV_REG_PROG_COUNTER) != ADV_MCODE_START_ADDR) {
742241492Sjhb		mtx_unlock(&adv->lock);
743241492Sjhb		device_printf(adv->dev,
744241492Sjhb		    "Unable to set program counter. Initialization failed\n");
74539217Sgibbs		return (1);
74639217Sgibbs	}
74739217Sgibbs
74839217Sgibbs	config_msw = ADV_INW(adv, ADV_CONFIG_MSW);
74939217Sgibbs	config_lsw = ADV_INW(adv, ADV_CONFIG_LSW);
75039217Sgibbs
75139217Sgibbs	if ((config_msw & ADV_CFG_MSW_CLR_MASK) != 0) {
75255945Sgibbs		config_msw &= ~ADV_CFG_MSW_CLR_MASK;
75339217Sgibbs		/*
75439217Sgibbs		 * XXX The Linux code flags this as an error,
75539217Sgibbs		 * but what should we report to the user???
75639217Sgibbs		 * It seems that clearing the config register
75739217Sgibbs		 * makes this error recoverable.
75839217Sgibbs		 */
75939217Sgibbs		ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw);
76039217Sgibbs	}
76139217Sgibbs
76239217Sgibbs	/* Suck in the configuration from the EEProm */
76339217Sgibbs	checksum = adv_get_eeprom_config(adv, &eeprom_config);
76439217Sgibbs
76539217Sgibbs	if (ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_AUTO_CONFIG) {
76639217Sgibbs		/*
76739217Sgibbs		 * XXX The Linux code sets a warning level for this
76839217Sgibbs		 * condition, yet nothing of meaning is printed to
76939217Sgibbs		 * the user.  What does this mean???
77039217Sgibbs		 */
77139217Sgibbs		if (adv->chip_version == 3) {
77255945Sgibbs			if (eeprom_config.cfg_lsw != config_lsw)
77355945Sgibbs				eeprom_config.cfg_lsw = config_lsw;
77439217Sgibbs			if (eeprom_config.cfg_msw != config_msw) {
77555945Sgibbs				eeprom_config.cfg_msw = config_msw;
77639217Sgibbs			}
77739217Sgibbs		}
77839217Sgibbs	}
77939217Sgibbs	if (checksum == eeprom_config.chksum) {
78055945Sgibbs
78139217Sgibbs		/* Range/Sanity checking */
78239217Sgibbs		if (eeprom_config.max_total_qng < ADV_MIN_TOTAL_QNG) {
78339217Sgibbs			eeprom_config.max_total_qng = ADV_MIN_TOTAL_QNG;
78439217Sgibbs		}
78539217Sgibbs		if (eeprom_config.max_total_qng > ADV_MAX_TOTAL_QNG) {
78639217Sgibbs			eeprom_config.max_total_qng = ADV_MAX_TOTAL_QNG;
78739217Sgibbs		}
78839217Sgibbs		if (eeprom_config.max_tag_qng > eeprom_config.max_total_qng) {
78939217Sgibbs			eeprom_config.max_tag_qng = eeprom_config.max_total_qng;
79039217Sgibbs		}
79139217Sgibbs		if (eeprom_config.max_tag_qng < ADV_MIN_TAG_Q_PER_DVC) {
79239217Sgibbs			eeprom_config.max_tag_qng = ADV_MIN_TAG_Q_PER_DVC;
79339217Sgibbs		}
79439217Sgibbs		adv->max_openings = eeprom_config.max_total_qng;
79539217Sgibbs		adv->user_disc_enable = eeprom_config.disc_enable;
79639217Sgibbs		adv->user_cmd_qng_enabled = eeprom_config.use_cmd_qng;
79739217Sgibbs		adv->isa_dma_speed = EEPROM_DMA_SPEED(eeprom_config);
79839217Sgibbs		adv->scsi_id = EEPROM_SCSIID(eeprom_config) & ADV_MAX_TID;
79939217Sgibbs		EEPROM_SET_SCSIID(eeprom_config, adv->scsi_id);
80039217Sgibbs		adv->control = eeprom_config.cntl;
80155945Sgibbs		for (i = 0; i <= ADV_MAX_TID; i++) {
80255945Sgibbs			u_int8_t sync_data;
80355945Sgibbs
80455945Sgibbs			if ((eeprom_config.init_sdtr & (0x1 << i)) == 0)
80555945Sgibbs				sync_data = 0;
80655945Sgibbs			else
80755945Sgibbs				sync_data = eeprom_config.sdtr_data[i];
80839217Sgibbs			adv_sdtr_to_period_offset(adv,
80955945Sgibbs						  sync_data,
81039217Sgibbs						  &adv->tinfo[i].user.period,
81139217Sgibbs						  &adv->tinfo[i].user.offset,
81239217Sgibbs						  i);
81355945Sgibbs		}
81455945Sgibbs		config_lsw = eeprom_config.cfg_lsw;
81555945Sgibbs		eeprom_config.cfg_msw = config_msw;
81639217Sgibbs	} else {
81739217Sgibbs		u_int8_t sync_data;
81839217Sgibbs
819241492Sjhb		device_printf(adv->dev, "Warning EEPROM Checksum mismatch. "
820241492Sjhb		       "Using default device parameters\n");
82139217Sgibbs
82239217Sgibbs		/* Set reasonable defaults since we can't read the EEPROM */
82339217Sgibbs		adv->isa_dma_speed = /*ADV_DEF_ISA_DMA_SPEED*/1;
82439217Sgibbs		adv->max_openings = ADV_DEF_MAX_TOTAL_QNG;
82539217Sgibbs		adv->disc_enable = TARGET_BIT_VECTOR_SET;
82639217Sgibbs		adv->user_disc_enable = TARGET_BIT_VECTOR_SET;
82739217Sgibbs		adv->cmd_qng_enabled = TARGET_BIT_VECTOR_SET;
82839217Sgibbs		adv->user_cmd_qng_enabled = TARGET_BIT_VECTOR_SET;
82939217Sgibbs		adv->scsi_id = 7;
83055945Sgibbs		adv->control = 0xFFFF;
83139217Sgibbs
83255945Sgibbs		if (adv->chip_version == ADV_CHIP_VER_PCI_ULTRA_3050)
83355945Sgibbs			/* Default to no Ultra to support the 3030 */
83455945Sgibbs			adv->control &= ~ADV_CNTL_SDTR_ENABLE_ULTRA;
83539217Sgibbs		sync_data = ADV_DEF_SDTR_OFFSET | (ADV_DEF_SDTR_INDEX << 4);
83655945Sgibbs		for (i = 0; i <= ADV_MAX_TID; i++) {
83739217Sgibbs			adv_sdtr_to_period_offset(adv, sync_data,
83839217Sgibbs						  &adv->tinfo[i].user.period,
83939217Sgibbs						  &adv->tinfo[i].user.offset,
84039217Sgibbs						  i);
84155945Sgibbs		}
84255945Sgibbs		config_lsw |= ADV_CFG_LSW_SCSI_PARITY_ON;
84339217Sgibbs	}
84455945Sgibbs	config_msw &= ~ADV_CFG_MSW_CLR_MASK;
84555945Sgibbs	config_lsw |= ADV_CFG_LSW_HOST_INT_ON;
84655945Sgibbs	if ((adv->type & (ADV_PCI|ADV_ULTRA)) == (ADV_PCI|ADV_ULTRA)
84755945Sgibbs	 && (adv->control & ADV_CNTL_SDTR_ENABLE_ULTRA) == 0)
84855945Sgibbs		/* 25ns or 10MHz */
84955945Sgibbs		max_sync = 25;
85055945Sgibbs	else
85155945Sgibbs		/* Unlimited */
85255945Sgibbs		max_sync = 0;
85355945Sgibbs	for (i = 0; i <= ADV_MAX_TID; i++) {
85455945Sgibbs		if (adv->tinfo[i].user.period < max_sync)
85555945Sgibbs			adv->tinfo[i].user.period = max_sync;
85655945Sgibbs	}
85739217Sgibbs
85855945Sgibbs	if (adv_test_external_lram(adv) == 0) {
85955945Sgibbs		if ((adv->type & (ADV_PCI|ADV_ULTRA)) == (ADV_PCI|ADV_ULTRA)) {
86055945Sgibbs			eeprom_config.max_total_qng =
86155945Sgibbs			    ADV_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
86255945Sgibbs			eeprom_config.max_tag_qng =
86355945Sgibbs			    ADV_MAX_PCI_ULTRA_INRAM_TAG_QNG;
86455945Sgibbs		} else {
86555945Sgibbs			eeprom_config.cfg_msw |= 0x0800;
86655945Sgibbs			config_msw |= 0x0800;
86755945Sgibbs			eeprom_config.max_total_qng =
86855945Sgibbs			     ADV_MAX_PCI_INRAM_TOTAL_QNG;
86955945Sgibbs			eeprom_config.max_tag_qng = ADV_MAX_INRAM_TAG_QNG;
87055945Sgibbs		}
87155945Sgibbs		adv->max_openings = eeprom_config.max_total_qng;
87255945Sgibbs	}
87355945Sgibbs	ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw);
87455945Sgibbs	ADV_OUTW(adv, ADV_CONFIG_LSW, config_lsw);
87555945Sgibbs#if 0
87655945Sgibbs	/*
87755945Sgibbs	 * Don't write the eeprom data back for now.
87855945Sgibbs	 * I'd rather not mess up the user's card.  We also don't
87955945Sgibbs	 * fully sanitize the eeprom settings above for the write-back
88055945Sgibbs	 * to be 100% correct.
88155945Sgibbs	 */
88239217Sgibbs	if (adv_set_eeprom_config(adv, &eeprom_config) != 0)
883241492Sjhb		device_printf(adv->dev,
884241492Sjhb		    "WARNING! Failure writing to EEPROM.\n");
88555945Sgibbs#endif
88639217Sgibbs
88739217Sgibbs	adv_set_chip_scsiid(adv, adv->scsi_id);
888241492Sjhb	if (adv_init_lram_and_mcode(adv)) {
889241492Sjhb		mtx_unlock(&adv->lock);
89039217Sgibbs		return (1);
891241492Sjhb	}
89239217Sgibbs
89339217Sgibbs	adv->disc_enable = adv->user_disc_enable;
89439217Sgibbs
89539217Sgibbs	adv_write_lram_8(adv, ADVV_DISC_ENABLE_B, adv->disc_enable);
89639217Sgibbs	for (i = 0; i <= ADV_MAX_TID; i++) {
89739217Sgibbs		/*
89839217Sgibbs		 * Start off in async mode.
89939217Sgibbs		 */
90039217Sgibbs		adv_set_syncrate(adv, /*struct cam_path */NULL,
90139217Sgibbs				 i, /*period*/0, /*offset*/0,
90239217Sgibbs				 ADV_TRANS_CUR);
90339217Sgibbs		/*
90439217Sgibbs		 * Enable the use of tagged commands on all targets.
90539217Sgibbs		 * This allows the kernel driver to make up it's own mind
90639217Sgibbs		 * as it sees fit to tag queue instead of having the
90739217Sgibbs		 * firmware try and second guess the tag_code settins.
90839217Sgibbs		 */
90939217Sgibbs		adv_write_lram_8(adv, ADVV_MAX_DVC_QNG_BEG + i,
91039217Sgibbs				 adv->max_openings);
91139217Sgibbs	}
91239217Sgibbs	adv_write_lram_8(adv, ADVV_USE_TAGGED_QNG_B, TARGET_BIT_VECTOR_SET);
91339217Sgibbs	adv_write_lram_8(adv, ADVV_CAN_TAGGED_QNG_B, TARGET_BIT_VECTOR_SET);
914241492Sjhb	device_printf(adv->dev,
915241492Sjhb	    "AdvanSys %s Host Adapter, SCSI ID %d, queue depth %d\n",
916241492Sjhb	    (adv->type & ADV_ULTRA) && (max_sync == 0)
917241492Sjhb	    ? "Ultra SCSI" : "SCSI",
918241492Sjhb	    adv->scsi_id, adv->max_openings);
919241492Sjhb	mtx_unlock(&adv->lock);
92039217Sgibbs	return (0);
92139217Sgibbs}
92239217Sgibbs
92339217Sgibbsvoid
92439217Sgibbsadv_intr(void *arg)
92539217Sgibbs{
92639217Sgibbs	struct	  adv_softc *adv;
927241492Sjhb
928241492Sjhb	adv = arg;
929241492Sjhb	mtx_lock(&adv->lock);
930241492Sjhb	adv_intr_locked(adv);
931241492Sjhb	mtx_unlock(&adv->lock);
932241492Sjhb}
933241492Sjhb
934241492Sjhbvoid
935241492Sjhbadv_intr_locked(struct adv_softc *adv)
936241492Sjhb{
93739217Sgibbs	u_int16_t chipstat;
93839217Sgibbs	u_int16_t saved_ram_addr;
93939217Sgibbs	u_int8_t  ctrl_reg;
94039217Sgibbs	u_int8_t  saved_ctrl_reg;
94139217Sgibbs	u_int8_t  host_flag;
94239217Sgibbs
943241492Sjhb	if (!dumping)
944241492Sjhb		mtx_assert(&adv->lock, MA_OWNED);
94555945Sgibbs	chipstat = ADV_INW(adv, ADV_CHIP_STATUS);
94655945Sgibbs
94755945Sgibbs	/* Is it for us? */
94855945Sgibbs	if ((chipstat & (ADV_CSW_INT_PENDING|ADV_CSW_SCSI_RESET_LATCH)) == 0)
94955945Sgibbs		return;
95055945Sgibbs
95139217Sgibbs	ctrl_reg = ADV_INB(adv, ADV_CHIP_CTRL);
95239217Sgibbs	saved_ctrl_reg = ctrl_reg & (~(ADV_CC_SCSI_RESET | ADV_CC_CHIP_RESET |
95339217Sgibbs				       ADV_CC_SINGLE_STEP | ADV_CC_DIAG |
95439217Sgibbs				       ADV_CC_TEST));
95539217Sgibbs
95655945Sgibbs	if ((chipstat & (ADV_CSW_SCSI_RESET_LATCH|ADV_CSW_SCSI_RESET_ACTIVE))) {
957241492Sjhb		device_printf(adv->dev, "Detected Bus Reset\n");
95855945Sgibbs		adv_reset_bus(adv, /*initiate_reset*/FALSE);
95955945Sgibbs		return;
96055945Sgibbs	}
96139217Sgibbs
96255945Sgibbs	if ((chipstat & ADV_CSW_INT_PENDING) != 0) {
96339217Sgibbs
96439217Sgibbs		saved_ram_addr = ADV_INW(adv, ADV_LRAM_ADDR);
96539217Sgibbs		host_flag = adv_read_lram_8(adv, ADVV_HOST_FLAG_B);
96639217Sgibbs		adv_write_lram_8(adv, ADVV_HOST_FLAG_B,
96739217Sgibbs				 host_flag | ADV_HOST_FLAG_IN_ISR);
96839217Sgibbs
96939217Sgibbs		adv_ack_interrupt(adv);
97039217Sgibbs
97155945Sgibbs		if ((chipstat & ADV_CSW_HALTED) != 0
97255945Sgibbs		 && (ctrl_reg & ADV_CC_SINGLE_STEP) != 0) {
97339217Sgibbs			adv_isr_chip_halted(adv);
97439217Sgibbs			saved_ctrl_reg &= ~ADV_CC_HALT;
97539217Sgibbs		} else {
97639217Sgibbs			adv_run_doneq(adv);
97739217Sgibbs		}
97839217Sgibbs		ADV_OUTW(adv, ADV_LRAM_ADDR, saved_ram_addr);
97939217Sgibbs#ifdef DIAGNOSTIC
98039217Sgibbs		if (ADV_INW(adv, ADV_LRAM_ADDR) != saved_ram_addr)
98139217Sgibbs			panic("adv_intr: Unable to set LRAM addr");
98239217Sgibbs#endif
98339217Sgibbs		adv_write_lram_8(adv, ADVV_HOST_FLAG_B, host_flag);
98439217Sgibbs	}
98539217Sgibbs
98639217Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, saved_ctrl_reg);
98739217Sgibbs}
98839217Sgibbs
989104094Sphkstatic void
99039217Sgibbsadv_run_doneq(struct adv_softc *adv)
99139217Sgibbs{
99239217Sgibbs	struct adv_q_done_info scsiq;
99339217Sgibbs	u_int		  doneq_head;
99439217Sgibbs	u_int		  done_qno;
99539217Sgibbs
99639217Sgibbs	doneq_head = adv_read_lram_16(adv, ADVV_DONE_Q_TAIL_W) & 0xFF;
99739217Sgibbs	done_qno = adv_read_lram_8(adv, ADV_QNO_TO_QADDR(doneq_head)
99839217Sgibbs				   + ADV_SCSIQ_B_FWD);
99939217Sgibbs	while (done_qno != ADV_QLINK_END) {
100039217Sgibbs		union ccb* ccb;
100155945Sgibbs		struct adv_ccb_info *cinfo;
100239217Sgibbs		u_int done_qaddr;
100339217Sgibbs		u_int sg_queue_cnt;
100439217Sgibbs
100539217Sgibbs		done_qaddr = ADV_QNO_TO_QADDR(done_qno);
100639217Sgibbs
100739217Sgibbs		/* Pull status from this request */
100839217Sgibbs		sg_queue_cnt = adv_copy_lram_doneq(adv, done_qaddr, &scsiq,
100939217Sgibbs						   adv->max_dma_count);
101039217Sgibbs
101139217Sgibbs		/* Mark it as free */
101239217Sgibbs		adv_write_lram_8(adv, done_qaddr + ADV_SCSIQ_B_STATUS,
101339505Sgibbs				 scsiq.q_status & ~(QS_READY|QS_ABORTED));
101439217Sgibbs
101539217Sgibbs		/* Process request based on retrieved info */
101639217Sgibbs		if ((scsiq.cntl & QC_SG_HEAD) != 0) {
101739217Sgibbs			u_int i;
101839217Sgibbs
101939217Sgibbs			/*
102039217Sgibbs			 * S/G based request.  Free all of the queue
102139217Sgibbs			 * structures that contained S/G information.
102239217Sgibbs			 */
102339217Sgibbs			for (i = 0; i < sg_queue_cnt; i++) {
102439217Sgibbs				done_qno = adv_read_lram_8(adv, done_qaddr
102539217Sgibbs							   + ADV_SCSIQ_B_FWD);
102639217Sgibbs
102739217Sgibbs#ifdef DIAGNOSTIC
102839505Sgibbs				if (done_qno == ADV_QLINK_END) {
102939217Sgibbs					panic("adv_qdone: Corrupted SG "
103039217Sgibbs					      "list encountered");
103139217Sgibbs				}
103239217Sgibbs#endif
103339505Sgibbs				done_qaddr = ADV_QNO_TO_QADDR(done_qno);
103439505Sgibbs
103539217Sgibbs				/* Mark SG queue as free */
103639217Sgibbs				adv_write_lram_8(adv, done_qaddr
103739217Sgibbs						 + ADV_SCSIQ_B_STATUS, QS_FREE);
103839217Sgibbs			}
103939217Sgibbs		} else
104039217Sgibbs			sg_queue_cnt = 0;
104139217Sgibbs#ifdef DIAGNOSTIC
104239505Sgibbs		if (adv->cur_active < (sg_queue_cnt + 1))
104339217Sgibbs			panic("adv_qdone: Attempting to free more "
104439217Sgibbs			      "queues than are active");
104539217Sgibbs#endif
104639217Sgibbs		adv->cur_active -= sg_queue_cnt + 1;
104739217Sgibbs
104839217Sgibbs		if ((scsiq.q_status != QS_DONE)
104939217Sgibbs		 && (scsiq.q_status & QS_ABORTED) == 0)
105039217Sgibbs			panic("adv_qdone: completed scsiq with unknown status");
105139217Sgibbs
105239217Sgibbs		scsiq.remain_bytes += scsiq.extra_bytes;
105339217Sgibbs
105439217Sgibbs		if ((scsiq.d3.done_stat == QD_WITH_ERROR) &&
105539217Sgibbs		    (scsiq.d3.host_stat == QHSTA_M_DATA_OVER_RUN)) {
105639217Sgibbs			if ((scsiq.cntl & (QC_DATA_IN|QC_DATA_OUT)) == 0) {
105739217Sgibbs				scsiq.d3.done_stat = QD_NO_ERROR;
105839217Sgibbs				scsiq.d3.host_stat = QHSTA_NO_ERROR;
105939217Sgibbs			}
106039217Sgibbs		}
106139217Sgibbs
106255945Sgibbs		cinfo = &adv->ccb_infos[scsiq.d2.ccb_index];
106355945Sgibbs		ccb = cinfo->ccb;
106439217Sgibbs		ccb->csio.resid = scsiq.remain_bytes;
106555945Sgibbs		adv_done(adv, ccb,
106639217Sgibbs			 scsiq.d3.done_stat, scsiq.d3.host_stat,
106739217Sgibbs			 scsiq.d3.scsi_stat, scsiq.q_no);
106839217Sgibbs
106939217Sgibbs		doneq_head = done_qno;
107040027Sgibbs		done_qno = adv_read_lram_8(adv, done_qaddr + ADV_SCSIQ_B_FWD);
107139217Sgibbs	}
107239217Sgibbs	adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, doneq_head);
107339217Sgibbs}
107439217Sgibbs
107539217Sgibbs
107639217Sgibbsvoid
107739217Sgibbsadv_done(struct adv_softc *adv, union ccb *ccb, u_int done_stat,
107839217Sgibbs	 u_int host_stat, u_int scsi_status, u_int q_no)
107939217Sgibbs{
108039217Sgibbs	struct	   adv_ccb_info *cinfo;
108139217Sgibbs
1082241492Sjhb	if (!dumping)
1083241492Sjhb		mtx_assert(&adv->lock, MA_OWNED);
108439217Sgibbs	cinfo = (struct adv_ccb_info *)ccb->ccb_h.ccb_cinfo_ptr;
108545443Sgibbs	LIST_REMOVE(&ccb->ccb_h, sim_links.le);
1086241492Sjhb	callout_stop(&cinfo->timer);
108739217Sgibbs	if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
1088115343Sscottl		bus_dmasync_op_t op;
108939217Sgibbs
109039217Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
109139217Sgibbs			op = BUS_DMASYNC_POSTREAD;
109239217Sgibbs		else
109339217Sgibbs			op = BUS_DMASYNC_POSTWRITE;
109439217Sgibbs		bus_dmamap_sync(adv->buffer_dmat, cinfo->dmamap, op);
109539217Sgibbs		bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap);
109639217Sgibbs	}
109739217Sgibbs
109839217Sgibbs	switch (done_stat) {
109939217Sgibbs	case QD_NO_ERROR:
110045443Sgibbs		if (host_stat == QHSTA_NO_ERROR) {
110139217Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP;
110239217Sgibbs			break;
110339217Sgibbs		}
110445443Sgibbs		xpt_print_path(ccb->ccb_h.path);
110545443Sgibbs		printf("adv_done - queue done without error, "
110645443Sgibbs		       "but host status non-zero(%x)\n", host_stat);
110745443Sgibbs		/*FALLTHROUGH*/
110839217Sgibbs	case QD_WITH_ERROR:
110939217Sgibbs		switch (host_stat) {
111045443Sgibbs		case QHSTA_M_TARGET_STATUS_BUSY:
111145443Sgibbs		case QHSTA_M_BAD_QUEUE_FULL_OR_BUSY:
111245443Sgibbs			/*
111345443Sgibbs			 * Assume that if we were a tagged transaction
111445443Sgibbs			 * the target reported queue full.  Otherwise,
111545443Sgibbs			 * report busy.  The firmware really should just
111645443Sgibbs			 * pass the original status back up to us even
111745443Sgibbs			 * if it thinks the target was in error for
111845443Sgibbs			 * returning this status as no other transactions
111945443Sgibbs			 * from this initiator are in effect, but this
112045443Sgibbs			 * ignores multi-initiator setups and there is
112145443Sgibbs			 * evidence that the firmware gets its per-device
1122298955Spfg			 * transaction counts screwed up occasionally.
112345443Sgibbs			 */
112445443Sgibbs			ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
112545443Sgibbs			if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0
112645443Sgibbs			 && host_stat != QHSTA_M_TARGET_STATUS_BUSY)
112745443Sgibbs				scsi_status = SCSI_STATUS_QUEUE_FULL;
112845443Sgibbs			else
112945443Sgibbs				scsi_status = SCSI_STATUS_BUSY;
113045443Sgibbs			adv_abort_ccb(adv, ccb->ccb_h.target_id,
113145443Sgibbs				      ccb->ccb_h.target_lun,
113245443Sgibbs				      /*ccb*/NULL, CAM_REQUEUE_REQ,
113345443Sgibbs				      /*queued_only*/TRUE);
113445443Sgibbs			/*FALLTHROUGH*/
113545443Sgibbs		case QHSTA_M_NO_AUTO_REQ_SENSE:
113639217Sgibbs		case QHSTA_NO_ERROR:
113739217Sgibbs			ccb->csio.scsi_status = scsi_status;
113839217Sgibbs			switch (scsi_status) {
113939217Sgibbs			case SCSI_STATUS_CHECK_COND:
114039217Sgibbs			case SCSI_STATUS_CMD_TERMINATED:
114139217Sgibbs				ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
114239217Sgibbs				/* Structure copy */
114339217Sgibbs				ccb->csio.sense_data =
114439217Sgibbs				    adv->sense_buffers[q_no - 1];
114539217Sgibbs				/* FALLTHROUGH */
114639217Sgibbs			case SCSI_STATUS_BUSY:
114739217Sgibbs			case SCSI_STATUS_RESERV_CONFLICT:
114839217Sgibbs			case SCSI_STATUS_QUEUE_FULL:
114939217Sgibbs			case SCSI_STATUS_COND_MET:
115039217Sgibbs			case SCSI_STATUS_INTERMED:
115139217Sgibbs			case SCSI_STATUS_INTERMED_COND_MET:
115239217Sgibbs				ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
115339217Sgibbs				break;
115439217Sgibbs			case SCSI_STATUS_OK:
115539217Sgibbs				ccb->ccb_h.status |= CAM_REQ_CMP;
115639217Sgibbs				break;
115739217Sgibbs			}
115839217Sgibbs			break;
115939217Sgibbs		case QHSTA_M_SEL_TIMEOUT:
116039217Sgibbs			ccb->ccb_h.status = CAM_SEL_TIMEOUT;
116139217Sgibbs			break;
116245443Sgibbs		case QHSTA_M_DATA_OVER_RUN:
116345443Sgibbs			ccb->ccb_h.status = CAM_DATA_RUN_ERR;
116445443Sgibbs			break;
116545443Sgibbs		case QHSTA_M_UNEXPECTED_BUS_FREE:
116645443Sgibbs			ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
116745443Sgibbs			break;
116845443Sgibbs		case QHSTA_M_BAD_BUS_PHASE_SEQ:
116945443Sgibbs			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
117045443Sgibbs			break;
117145443Sgibbs		case QHSTA_M_BAD_CMPL_STATUS_IN:
117245443Sgibbs			/* No command complete after a status message */
117345443Sgibbs			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
117445443Sgibbs			break;
117545443Sgibbs		case QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT:
117645443Sgibbs		case QHSTA_M_WTM_TIMEOUT:
117745443Sgibbs		case QHSTA_M_HUNG_REQ_SCSI_BUS_RESET:
117845443Sgibbs			/* The SCSI bus hung in a phase */
117945443Sgibbs			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
118055945Sgibbs			adv_reset_bus(adv, /*initiate_reset*/TRUE);
118145443Sgibbs			break;
118245846Sgibbs		case QHSTA_M_AUTO_REQ_SENSE_FAIL:
118345846Sgibbs			ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
118445846Sgibbs			break;
118545443Sgibbs		case QHSTA_D_QDONE_SG_LIST_CORRUPTED:
118645443Sgibbs		case QHSTA_D_ASC_DVC_ERROR_CODE_SET:
118745443Sgibbs		case QHSTA_D_HOST_ABORT_FAILED:
118845443Sgibbs		case QHSTA_D_EXE_SCSI_Q_FAILED:
118945443Sgibbs		case QHSTA_D_ASPI_NO_BUF_POOL:
119045443Sgibbs		case QHSTA_M_BAD_TAG_CODE:
119145443Sgibbs		case QHSTA_D_LRAM_CMP_ERROR:
119245443Sgibbs		case QHSTA_M_MICRO_CODE_ERROR_HALT:
119339217Sgibbs		default:
119445443Sgibbs			panic("%s: Unhandled Host status error %x",
1195241492Sjhb			    device_get_nameunit(adv->dev), host_stat);
119645443Sgibbs			/* NOTREACHED */
119739217Sgibbs		}
119839217Sgibbs		break;
119939217Sgibbs
120039217Sgibbs	case QD_ABORTED_BY_HOST:
120139217Sgibbs		/* Don't clobber any, more explicit, error codes we've set */
120239217Sgibbs		if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG)
120339217Sgibbs			ccb->ccb_h.status = CAM_REQ_ABORTED;
120439217Sgibbs		break;
120539217Sgibbs
120639217Sgibbs	default:
120740733Sgibbs		xpt_print_path(ccb->ccb_h.path);
120840733Sgibbs		printf("adv_done - queue done with unknown status %x:%x\n",
120940733Sgibbs		       done_stat, host_stat);
121039217Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
121139217Sgibbs		break;
121239217Sgibbs	}
121355945Sgibbs	adv_clear_state(adv, ccb);
121439217Sgibbs	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP
121539217Sgibbs	 && (ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
121639217Sgibbs		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
121739217Sgibbs		ccb->ccb_h.status |= CAM_DEV_QFRZN;
121839217Sgibbs	}
121939217Sgibbs	adv_free_ccb_info(adv, cinfo);
122055945Sgibbs	/*
122155945Sgibbs	 * Null this out so that we catch driver bugs that cause a
122255945Sgibbs	 * ccb to be completed twice.
122355945Sgibbs	 */
122455945Sgibbs	ccb->ccb_h.ccb_cinfo_ptr = NULL;
122539217Sgibbs	ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
122639217Sgibbs	xpt_done(ccb);
122739217Sgibbs}
122839217Sgibbs
122939217Sgibbs/*
123039217Sgibbs * Function to poll for command completion when
123139217Sgibbs * interrupts are disabled (crash dumps)
123239217Sgibbs */
123339217Sgibbsstatic void
123439217Sgibbsadv_poll(struct cam_sim *sim)
123539217Sgibbs{
1236241492Sjhb
1237241492Sjhb	adv_intr_locked(cam_sim_softc(sim));
123839217Sgibbs}
123939217Sgibbs
124039217Sgibbs/*
124139217Sgibbs * Attach all the sub-devices we can find
124239217Sgibbs */
124339217Sgibbsint
124439217Sgibbsadv_attach(adv)
124539217Sgibbs	struct adv_softc *adv;
124639217Sgibbs{
124739217Sgibbs	struct ccb_setasync csa;
124839217Sgibbs	struct cam_devq *devq;
124955945Sgibbs	int max_sg;
125039217Sgibbs
125139217Sgibbs	/*
125255945Sgibbs	 * Allocate an array of ccb mapping structures.  We put the
125355945Sgibbs	 * index of the ccb_info structure into the queue representing
125455945Sgibbs	 * a transaction and use it for mapping the queue to the
125555945Sgibbs	 * upper level SCSI transaction it represents.
125655945Sgibbs	 */
125755945Sgibbs	adv->ccb_infos = malloc(sizeof(*adv->ccb_infos) * adv->max_openings,
125855945Sgibbs				M_DEVBUF, M_NOWAIT);
125955945Sgibbs
126055945Sgibbs	if (adv->ccb_infos == NULL)
126160818Snyan		return (ENOMEM);
126255945Sgibbs
126355945Sgibbs	adv->init_level++;
126455945Sgibbs
126555945Sgibbs	/*
126639217Sgibbs	 * Create our DMA tags.  These tags define the kinds of device
126761686Salex	 * accessible memory allocations and memory mappings we will
126839217Sgibbs	 * need to perform during normal operation.
126939217Sgibbs	 *
127039217Sgibbs	 * Unless we need to further restrict the allocation, we rely
127139217Sgibbs	 * on the restrictions of the parent dmat, hence the common
127239217Sgibbs	 * use of MAXADDR and MAXSIZE.
127355945Sgibbs	 *
127455945Sgibbs	 * The ASC boards use chains of "queues" (the transactional
127555945Sgibbs	 * resources on the board) to represent long S/G lists.
127655945Sgibbs	 * The first queue represents the command and holds a
127755945Sgibbs	 * single address and data pair.  The queues that follow
127855945Sgibbs	 * can each hold ADV_SG_LIST_PER_Q entries.  Given the
127955945Sgibbs	 * total number of queues, we can express the largest
128055945Sgibbs	 * transaction we can map.  We reserve a few queues for
128155945Sgibbs	 * error recovery.  Take those into account as well.
128255945Sgibbs	 *
128355945Sgibbs	 * There is a way to take an interrupt to download the
128455945Sgibbs	 * next batch of S/G entries if there are more than 255
128555945Sgibbs	 * of them (the counter in the queue structure is a u_int8_t).
128655945Sgibbs	 * We don't use this feature, so limit the S/G list size
128755945Sgibbs	 * accordingly.
128839217Sgibbs	 */
128955945Sgibbs	max_sg = (adv->max_openings - ADV_MIN_FREE_Q - 1) * ADV_SG_LIST_PER_Q;
129055945Sgibbs	if (max_sg > 255)
129155945Sgibbs		max_sg = 255;
129239217Sgibbs
129339217Sgibbs	/* DMA tag for mapping buffers into device visible space. */
1294112782Smdodd	if (bus_dma_tag_create(
1295112782Smdodd			/* parent	*/ adv->parent_dmat,
1296112782Smdodd			/* alignment	*/ 1,
1297112782Smdodd			/* boundary	*/ 0,
1298112782Smdodd			/* lowaddr	*/ BUS_SPACE_MAXADDR,
1299112782Smdodd			/* highaddr	*/ BUS_SPACE_MAXADDR,
1300112782Smdodd			/* filter	*/ NULL,
1301112782Smdodd			/* filterarg	*/ NULL,
1302195534Sscottl			/* maxsize	*/ ADV_MAXPHYS,
1303112782Smdodd			/* nsegments	*/ max_sg,
1304112782Smdodd			/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
1305112782Smdodd			/* flags	*/ BUS_DMA_ALLOCNOW,
1306117126Sscottl			/* lockfunc	*/ busdma_lock_mutex,
1307241492Sjhb			/* lockarg	*/ &adv->lock,
1308112782Smdodd			&adv->buffer_dmat) != 0) {
130960818Snyan		return (ENXIO);
131039217Sgibbs	}
131139217Sgibbs	adv->init_level++;
131239217Sgibbs
131339217Sgibbs	/* DMA tag for our sense buffers */
1314112782Smdodd	if (bus_dma_tag_create(
1315112782Smdodd			/* parent	*/ adv->parent_dmat,
1316112782Smdodd			/* alignment	*/ 1,
1317112782Smdodd			/* boundary	*/ 0,
1318112782Smdodd			/* lowaddr	*/ BUS_SPACE_MAXADDR,
1319112782Smdodd			/* highaddr	*/ BUS_SPACE_MAXADDR,
1320112782Smdodd			/* filter	*/ NULL,
1321112782Smdodd			/* filterarg	*/ NULL,
1322112782Smdodd			/* maxsize	*/ sizeof(struct scsi_sense_data) *
1323112782Smdodd					   adv->max_openings,
1324112782Smdodd			/* nsegments	*/ 1,
1325112782Smdodd			/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
1326112782Smdodd			/* flags	*/ 0,
1327117126Sscottl			/* lockfunc	*/ busdma_lock_mutex,
1328241492Sjhb			/* lockarg	*/ &adv->lock,
1329112782Smdodd			&adv->sense_dmat) != 0) {
133060818Snyan		return (ENXIO);
133139217Sgibbs        }
133239217Sgibbs
133339217Sgibbs	adv->init_level++;
133439217Sgibbs
133539217Sgibbs	/* Allocation for our sense buffers */
133639217Sgibbs	if (bus_dmamem_alloc(adv->sense_dmat, (void **)&adv->sense_buffers,
133739217Sgibbs			     BUS_DMA_NOWAIT, &adv->sense_dmamap) != 0) {
133860818Snyan		return (ENOMEM);
133939217Sgibbs	}
134039217Sgibbs
134139217Sgibbs	adv->init_level++;
134239217Sgibbs
134339217Sgibbs	/* And permanently map them */
134439217Sgibbs	bus_dmamap_load(adv->sense_dmat, adv->sense_dmamap,
134539217Sgibbs       			adv->sense_buffers,
134639217Sgibbs			sizeof(struct scsi_sense_data)*adv->max_openings,
134739217Sgibbs			adv_map, &adv->sense_physbase, /*flags*/0);
134839217Sgibbs
134939217Sgibbs	adv->init_level++;
135039217Sgibbs
135139217Sgibbs	/*
135239217Sgibbs	 * Fire up the chip
135339217Sgibbs	 */
135439217Sgibbs	if (adv_start_chip(adv) != 1) {
1355241492Sjhb		device_printf(adv->dev,
1356241492Sjhb		    "Unable to start on board processor. Aborting.\n");
135760818Snyan		return (ENXIO);
135839217Sgibbs	}
135939217Sgibbs
136039217Sgibbs	/*
136139217Sgibbs	 * Create the device queue for our SIM.
136239217Sgibbs	 */
136339217Sgibbs	devq = cam_simq_alloc(adv->max_openings);
136439217Sgibbs	if (devq == NULL)
136560818Snyan		return (ENOMEM);
136639217Sgibbs
136739217Sgibbs	/*
136839217Sgibbs	 * Construct our SIM entry.
136939217Sgibbs	 */
1370241492Sjhb	adv->sim = cam_sim_alloc(adv_action, adv_poll, "adv", adv,
1371241492Sjhb	    device_get_unit(adv->dev), &adv->lock, 1, adv->max_openings, devq);
137239217Sgibbs	if (adv->sim == NULL)
137360818Snyan		return (ENOMEM);
137439217Sgibbs
137539217Sgibbs	/*
137639217Sgibbs	 * Register the bus.
137739217Sgibbs	 *
137839217Sgibbs	 * XXX Twin Channel EISA Cards???
137939217Sgibbs	 */
1380241492Sjhb	mtx_lock(&adv->lock);
1381170872Sscottl	if (xpt_bus_register(adv->sim, adv->dev, 0) != CAM_SUCCESS) {
138239217Sgibbs		cam_sim_free(adv->sim, /*free devq*/TRUE);
1383241492Sjhb		mtx_unlock(&adv->lock);
138460818Snyan		return (ENXIO);
138539217Sgibbs	}
138639217Sgibbs
138739217Sgibbs	if (xpt_create_path(&adv->path, /*periph*/NULL, cam_sim_path(adv->sim),
138839217Sgibbs			    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD)
138960818Snyan	    != CAM_REQ_CMP) {
139060818Snyan		xpt_bus_deregister(cam_sim_path(adv->sim));
139160818Snyan		cam_sim_free(adv->sim, /*free devq*/TRUE);
1392241492Sjhb		mtx_unlock(&adv->lock);
139360818Snyan		return (ENXIO);
139439217Sgibbs	}
139539217Sgibbs
139660818Snyan	xpt_setup_ccb(&csa.ccb_h, adv->path, /*priority*/5);
139760818Snyan	csa.ccb_h.func_code = XPT_SASYNC_CB;
139860818Snyan	csa.event_enable = AC_FOUND_DEVICE|AC_LOST_DEVICE;
139960818Snyan	csa.callback = advasync;
140060818Snyan	csa.callback_arg = adv;
140160818Snyan	xpt_action((union ccb *)&csa);
1402241492Sjhb	mtx_unlock(&adv->lock);
140339217Sgibbs	return (0);
140439217Sgibbs}
1405165102SmjacobMODULE_DEPEND(adv, cam, 1, 1, 1);
1406