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: releng/10.3/sys/dev/advansys/advansys.c 275982 2014-12-21 03:06:11Z smh $");
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;
171275982Ssmh				callout_reset_sbt(&cinfo->timer,
172275982Ssmh				    SBT_1MS * ccb_h->timeout, 0,
173275982Ssmh				    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_TARGET_IO:	/* Execute target I/O request */
23739217Sgibbs	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
23839217Sgibbs	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/
23939217Sgibbs	case XPT_EN_LUN:		/* Enable LUN as a target */
24039217Sgibbs	case XPT_ABORT:			/* Abort the specified CCB */
24139217Sgibbs		/* XXX Implement */
24239217Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
24339217Sgibbs		xpt_done(ccb);
24439217Sgibbs		break;
245163816Smjacob#define	IS_CURRENT_SETTINGS(c)	(c->type == CTS_TYPE_CURRENT_SETTINGS)
246163816Smjacob#define	IS_USER_SETTINGS(c)	(c->type == CTS_TYPE_USER_SETTINGS)
24739217Sgibbs	case XPT_SET_TRAN_SETTINGS:
24839217Sgibbs	{
249163816Smjacob		struct ccb_trans_settings_scsi *scsi;
250163816Smjacob		struct ccb_trans_settings_spi *spi;
25139217Sgibbs		struct	 ccb_trans_settings *cts;
25239217Sgibbs		target_bit_vector targ_mask;
25346581Sken		struct adv_transinfo *tconf;
25439217Sgibbs		u_int	 update_type;
25539217Sgibbs
25639217Sgibbs		cts = &ccb->cts;
25739217Sgibbs		targ_mask = ADV_TID_TO_TARGET_MASK(cts->ccb_h.target_id);
25839217Sgibbs		update_type = 0;
25946581Sken
26046581Sken		/*
26146581Sken		 * The user must specify which type of settings he wishes
26246581Sken		 * to change.
26346581Sken		 */
264163816Smjacob		if (IS_CURRENT_SETTINGS(cts) && !IS_USER_SETTINGS(cts)) {
26546581Sken			tconf = &adv->tinfo[cts->ccb_h.target_id].current;
26639217Sgibbs			update_type |= ADV_TRANS_GOAL;
267163816Smjacob		} else if (IS_USER_SETTINGS(cts) && !IS_CURRENT_SETTINGS(cts)) {
26846581Sken			tconf = &adv->tinfo[cts->ccb_h.target_id].user;
26939217Sgibbs			update_type |= ADV_TRANS_USER;
27046581Sken		} else {
27146581Sken			ccb->ccb_h.status = CAM_REQ_INVALID;
27246581Sken			break;
27346581Sken		}
27439217Sgibbs
275163816Smjacob		scsi = &cts->proto_specific.scsi;
276163816Smjacob		spi = &cts->xport_specific.spi;
277163816Smjacob		if ((update_type & ADV_TRANS_GOAL) != 0) {
278163816Smjacob			if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
279163816Smjacob				if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0)
280163816Smjacob					adv->disc_enable |= targ_mask;
281163816Smjacob				else
282163816Smjacob					adv->disc_enable &= ~targ_mask;
283163816Smjacob				adv_write_lram_8(adv, ADVV_DISC_ENABLE_B,
284163816Smjacob						 adv->disc_enable);
285163816Smjacob			}
28639217Sgibbs
287163816Smjacob			if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
288163816Smjacob				if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0)
289163816Smjacob					adv->cmd_qng_enabled |= targ_mask;
290163816Smjacob				else
291163816Smjacob					adv->cmd_qng_enabled &= ~targ_mask;
292163816Smjacob			}
293163816Smjacob		}
294163816Smjacob
295163816Smjacob		if ((update_type & ADV_TRANS_USER) != 0) {
296163816Smjacob			if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
297163816Smjacob				if ((spi->flags & CTS_SPI_VALID_DISC) != 0)
298163816Smjacob					adv->user_disc_enable |= targ_mask;
299163816Smjacob				else
300163816Smjacob					adv->user_disc_enable &= ~targ_mask;
301163816Smjacob			}
302163816Smjacob
303163816Smjacob			if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
304163816Smjacob				if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0)
305163816Smjacob					adv->user_cmd_qng_enabled |= targ_mask;
306163816Smjacob				else
307163816Smjacob					adv->user_cmd_qng_enabled &= ~targ_mask;
308163816Smjacob			}
309163816Smjacob		}
310163816Smjacob
311163816Smjacob		/*
312163816Smjacob		 * If the user specifies either the sync rate, or offset,
313163816Smjacob		 * but not both, the unspecified parameter defaults to its
314163816Smjacob		 * current value in transfer negotiations.
315163816Smjacob		 */
316163816Smjacob		if (((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0)
317163816Smjacob		 || ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)) {
318163816Smjacob			/*
319163816Smjacob			 * If the user provided a sync rate but no offset,
320163816Smjacob			 * use the current offset.
321163816Smjacob			 */
322163816Smjacob			if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0)
323163816Smjacob				spi->sync_offset = tconf->offset;
324163816Smjacob
325163816Smjacob			/*
326163816Smjacob			 * If the user provided an offset but no sync rate,
327163816Smjacob			 * use the current sync rate.
328163816Smjacob			 */
329163816Smjacob			if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0)
330163816Smjacob				spi->sync_period = tconf->period;
331163816Smjacob
332163816Smjacob			adv_period_offset_to_sdtr(adv, &spi->sync_period,
333163816Smjacob						  &spi->sync_offset,
334163816Smjacob						  cts->ccb_h.target_id);
335163816Smjacob
336163816Smjacob			adv_set_syncrate(adv, /*struct cam_path */NULL,
337163816Smjacob					 cts->ccb_h.target_id, spi->sync_period,
338163816Smjacob					 spi->sync_offset, update_type);
339163816Smjacob		}
34039217Sgibbs
34139217Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
34239217Sgibbs		xpt_done(ccb);
34339217Sgibbs		break;
34439217Sgibbs	}
34539217Sgibbs	case XPT_GET_TRAN_SETTINGS:
34639217Sgibbs	/* Get default/user set transfer settings for the target */
34739217Sgibbs	{
348163816Smjacob		struct ccb_trans_settings_scsi *scsi;
349163816Smjacob		struct ccb_trans_settings_spi *spi;
35039217Sgibbs		struct ccb_trans_settings *cts;
35139217Sgibbs		struct adv_transinfo *tconf;
35239217Sgibbs		target_bit_vector target_mask;
35339217Sgibbs
35439217Sgibbs		cts = &ccb->cts;
35539217Sgibbs		target_mask = ADV_TID_TO_TARGET_MASK(cts->ccb_h.target_id);
35639217Sgibbs
357163816Smjacob		scsi = &cts->proto_specific.scsi;
358163816Smjacob		spi = &cts->xport_specific.spi;
35939217Sgibbs
360163816Smjacob		cts->protocol = PROTO_SCSI;
361163816Smjacob		cts->protocol_version = SCSI_REV_2;
362163816Smjacob		cts->transport = XPORT_SPI;
363163816Smjacob		cts->transport_version = 2;
364163816Smjacob
365163816Smjacob		scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
366163816Smjacob		spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
367163816Smjacob
368163816Smjacob		if (cts->type == CTS_TYPE_CURRENT_SETTINGS) {
369163816Smjacob			tconf = &adv->tinfo[cts->ccb_h.target_id].current;
370163816Smjacob			if ((adv->disc_enable & target_mask) != 0)
371163816Smjacob				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
372163816Smjacob			if ((adv->cmd_qng_enabled & target_mask) != 0)
373163816Smjacob				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
374163816Smjacob		} else {
375163816Smjacob			tconf = &adv->tinfo[cts->ccb_h.target_id].user;
376163816Smjacob			if ((adv->user_disc_enable & target_mask) != 0)
377163816Smjacob				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
378163816Smjacob			if ((adv->user_cmd_qng_enabled & target_mask) != 0)
379163816Smjacob				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
380163816Smjacob		}
381163816Smjacob		spi->sync_period = tconf->period;
382163816Smjacob		spi->sync_offset = tconf->offset;
383163816Smjacob		spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
384163816Smjacob		spi->valid = CTS_SPI_VALID_SYNC_RATE
385163816Smjacob			   | CTS_SPI_VALID_SYNC_OFFSET
386163816Smjacob			   | CTS_SPI_VALID_BUS_WIDTH
387163816Smjacob			   | CTS_SPI_VALID_DISC;
388163816Smjacob		scsi->valid = CTS_SCSI_VALID_TQ;
38939217Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
39039217Sgibbs		xpt_done(ccb);
39139217Sgibbs		break;
39239217Sgibbs	}
39339217Sgibbs	case XPT_CALC_GEOMETRY:
39439217Sgibbs	{
39539217Sgibbs		int	  extended;
39639217Sgibbs
39739217Sgibbs		extended = (adv->control & ADV_CNTL_BIOS_GT_1GB) != 0;
398116351Snjl		cam_calc_geometry(&ccb->ccg, extended);
39939217Sgibbs		xpt_done(ccb);
40039217Sgibbs		break;
40139217Sgibbs	}
40239217Sgibbs	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
40339217Sgibbs	{
40439217Sgibbs
40539217Sgibbs		adv_stop_execution(adv);
40655945Sgibbs		adv_reset_bus(adv, /*initiate_reset*/TRUE);
40739217Sgibbs		adv_start_execution(adv);
40839217Sgibbs
40939217Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
41039217Sgibbs		xpt_done(ccb);
41139217Sgibbs		break;
41239217Sgibbs	}
41339217Sgibbs	case XPT_TERM_IO:		/* Terminate the I/O process */
41439217Sgibbs		/* XXX Implement */
41539217Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
41639217Sgibbs		xpt_done(ccb);
41739217Sgibbs		break;
41839217Sgibbs	case XPT_PATH_INQ:		/* Path routing inquiry */
41939217Sgibbs	{
42039217Sgibbs		struct ccb_pathinq *cpi = &ccb->cpi;
42139217Sgibbs
42239217Sgibbs		cpi->version_num = 1; /* XXX??? */
42339217Sgibbs		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE;
42439217Sgibbs		cpi->target_sprt = 0;
42539217Sgibbs		cpi->hba_misc = 0;
42639217Sgibbs		cpi->hba_eng_cnt = 0;
42739217Sgibbs		cpi->max_target = 7;
42839217Sgibbs		cpi->max_lun = 7;
42939217Sgibbs		cpi->initiator_id = adv->scsi_id;
43039217Sgibbs		cpi->bus_id = cam_sim_bus(sim);
43146581Sken		cpi->base_transfer_speed = 3300;
43239217Sgibbs		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
43339217Sgibbs		strncpy(cpi->hba_vid, "Advansys", HBA_IDLEN);
43439217Sgibbs		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
43539217Sgibbs		cpi->unit_number = cam_sim_unit(sim);
43639217Sgibbs		cpi->ccb_h.status = CAM_REQ_CMP;
437163816Smjacob                cpi->transport = XPORT_SPI;
438163816Smjacob                cpi->transport_version = 2;
439163816Smjacob                cpi->protocol = PROTO_SCSI;
440163816Smjacob                cpi->protocol_version = SCSI_REV_2;
44139217Sgibbs		xpt_done(ccb);
44239217Sgibbs		break;
44339217Sgibbs	}
44439217Sgibbs	default:
44539217Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
44639217Sgibbs		xpt_done(ccb);
44739217Sgibbs		break;
44839217Sgibbs	}
44939217Sgibbs}
45039217Sgibbs
45139217Sgibbs/*
45239217Sgibbs * Currently, the output of bus_dmammap_load suits our needs just
45339217Sgibbs * fine, but should it change, we'd need to do something here.
45439217Sgibbs */
45539217Sgibbs#define adv_fixup_dmasegs(adv, dm_segs) (struct adv_sg_entry *)(dm_segs)
45639217Sgibbs
45739217Sgibbsstatic void
45839217Sgibbsadv_execute_ccb(void *arg, bus_dma_segment_t *dm_segs,
45939217Sgibbs		int nsegments, int error)
46039217Sgibbs{
46139217Sgibbs	struct	ccb_scsiio *csio;
46239217Sgibbs	struct	ccb_hdr *ccb_h;
46339217Sgibbs	struct	cam_sim *sim;
46439217Sgibbs        struct	adv_softc *adv;
46539217Sgibbs	struct	adv_ccb_info *cinfo;
46639217Sgibbs	struct	adv_scsi_q scsiq;
46739217Sgibbs	struct	adv_sg_head sghead;
46839217Sgibbs
46939217Sgibbs	csio = (struct ccb_scsiio *)arg;
47039217Sgibbs	ccb_h = &csio->ccb_h;
47139217Sgibbs	sim = xpt_path_sim(ccb_h->path);
47239217Sgibbs	adv = (struct adv_softc *)cam_sim_softc(sim);
47339217Sgibbs	cinfo = (struct adv_ccb_info *)csio->ccb_h.ccb_cinfo_ptr;
474241492Sjhb	if (!dumping)
475241492Sjhb		mtx_assert(&adv->lock, MA_OWNED);
47639217Sgibbs
47755945Sgibbs	/*
47855945Sgibbs	 * Setup our done routine to release the simq on
47955945Sgibbs	 * the next ccb that completes.
48055945Sgibbs	 */
48155945Sgibbs	if ((adv->state & ADV_BUSDMA_BLOCK) != 0)
48255945Sgibbs		adv->state |= ADV_BUSDMA_BLOCK_CLEARED;
48355945Sgibbs
48439217Sgibbs	if ((ccb_h->flags & CAM_CDB_POINTER) != 0) {
48539217Sgibbs		if ((ccb_h->flags & CAM_CDB_PHYS) == 0) {
48639217Sgibbs			/* XXX Need phystovirt!!!! */
48739217Sgibbs			/* How about pmap_kenter??? */
48839217Sgibbs			scsiq.cdbptr = csio->cdb_io.cdb_ptr;
48939217Sgibbs		} else {
49039217Sgibbs			scsiq.cdbptr = csio->cdb_io.cdb_ptr;
49139217Sgibbs		}
49239217Sgibbs	} else {
49339217Sgibbs		scsiq.cdbptr = csio->cdb_io.cdb_bytes;
49439217Sgibbs	}
49539217Sgibbs	/*
49639217Sgibbs	 * Build up the request
49739217Sgibbs	 */
49839217Sgibbs	scsiq.q1.status = 0;
49939217Sgibbs	scsiq.q1.q_no = 0;
50039217Sgibbs	scsiq.q1.cntl = 0;
50139217Sgibbs	scsiq.q1.sg_queue_cnt = 0;
50239217Sgibbs	scsiq.q1.target_id = ADV_TID_TO_TARGET_MASK(ccb_h->target_id);
50339217Sgibbs	scsiq.q1.target_lun = ccb_h->target_lun;
50439217Sgibbs	scsiq.q1.sense_len = csio->sense_len;
50539217Sgibbs	scsiq.q1.extra_bytes = 0;
50655945Sgibbs	scsiq.q2.ccb_index = cinfo - adv->ccb_infos;
50739217Sgibbs	scsiq.q2.target_ix = ADV_TIDLUN_TO_IX(ccb_h->target_id,
50839217Sgibbs					      ccb_h->target_lun);
50939217Sgibbs	scsiq.q2.flag = 0;
51039217Sgibbs	scsiq.q2.cdb_len = csio->cdb_len;
51139217Sgibbs	if ((ccb_h->flags & CAM_TAG_ACTION_VALID) != 0)
51239217Sgibbs		scsiq.q2.tag_code = csio->tag_action;
51339217Sgibbs	else
51439217Sgibbs		scsiq.q2.tag_code = 0;
51539217Sgibbs	scsiq.q2.vm_id = 0;
51639217Sgibbs
51739217Sgibbs	if (nsegments != 0) {
518115343Sscottl		bus_dmasync_op_t op;
51939217Sgibbs
52039217Sgibbs		scsiq.q1.data_addr = dm_segs->ds_addr;
52139217Sgibbs                scsiq.q1.data_cnt = dm_segs->ds_len;
52239217Sgibbs		if (nsegments > 1) {
52339217Sgibbs			scsiq.q1.cntl |= QC_SG_HEAD;
52439217Sgibbs			sghead.entry_cnt
52539217Sgibbs			    = sghead.entry_to_copy
52639217Sgibbs			    = nsegments;
52739217Sgibbs			sghead.res = 0;
52839217Sgibbs			sghead.sg_list = adv_fixup_dmasegs(adv, dm_segs);
52939217Sgibbs			scsiq.sg_head = &sghead;
53039217Sgibbs		} else {
53139217Sgibbs			scsiq.sg_head = NULL;
53239217Sgibbs		}
53339217Sgibbs		if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN)
53439217Sgibbs			op = BUS_DMASYNC_PREREAD;
53539217Sgibbs		else
53639217Sgibbs			op = BUS_DMASYNC_PREWRITE;
53739217Sgibbs		bus_dmamap_sync(adv->buffer_dmat, cinfo->dmamap, op);
53839217Sgibbs	} else {
53939217Sgibbs		scsiq.q1.data_addr = 0;
54039217Sgibbs		scsiq.q1.data_cnt = 0;
54139217Sgibbs		scsiq.sg_head = NULL;
54239217Sgibbs	}
54339217Sgibbs
54440027Sgibbs	/*
54540027Sgibbs	 * Last time we need to check if this SCB needs to
54640027Sgibbs	 * be aborted.
54740027Sgibbs	 */
54840027Sgibbs	if (ccb_h->status != CAM_REQ_INPROG) {
54955945Sgibbs		if (nsegments != 0)
55040027Sgibbs			bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap);
55155945Sgibbs		adv_clear_state(adv, (union ccb *)csio);
55240027Sgibbs		adv_free_ccb_info(adv, cinfo);
55340027Sgibbs		xpt_done((union ccb *)csio);
55440027Sgibbs		return;
55540027Sgibbs	}
55640027Sgibbs
55739217Sgibbs	if (adv_execute_scsi_queue(adv, &scsiq, csio->dxfer_len) != 0) {
55839217Sgibbs		/* Temporary resource shortage */
55955945Sgibbs		adv_set_state(adv, ADV_RESOURCE_SHORTAGE);
56055945Sgibbs		if (nsegments != 0)
56139217Sgibbs			bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap);
56255945Sgibbs		csio->ccb_h.status = CAM_REQUEUE_REQ;
56355945Sgibbs		adv_clear_state(adv, (union ccb *)csio);
56439217Sgibbs		adv_free_ccb_info(adv, cinfo);
56539217Sgibbs		xpt_done((union ccb *)csio);
56639217Sgibbs		return;
56739217Sgibbs	}
56840027Sgibbs	cinfo->state |= ACCB_ACTIVE;
56939217Sgibbs	ccb_h->status |= CAM_SIM_QUEUED;
57039217Sgibbs	LIST_INSERT_HEAD(&adv->pending_ccbs, ccb_h, sim_links.le);
57139217Sgibbs	/* Schedule our timeout */
572275982Ssmh	callout_reset_sbt(&cinfo->timer, SBT_1MS * ccb_h->timeout, 0,
573275982Ssmh	    adv_timeout, csio, 0);
57439217Sgibbs}
57539217Sgibbs
57639217Sgibbsstatic struct adv_ccb_info *
57739217Sgibbsadv_alloc_ccb_info(struct adv_softc *adv)
57839217Sgibbs{
57939217Sgibbs	int error;
58039217Sgibbs	struct adv_ccb_info *cinfo;
58139217Sgibbs
58255945Sgibbs	cinfo = &adv->ccb_infos[adv->ccb_infos_allocated];
58339217Sgibbs	cinfo->state = ACCB_FREE;
584241492Sjhb	callout_init_mtx(&cinfo->timer, &adv->lock, 0);
58539217Sgibbs	error = bus_dmamap_create(adv->buffer_dmat, /*flags*/0,
58639217Sgibbs				  &cinfo->dmamap);
58739217Sgibbs	if (error != 0) {
588241492Sjhb		device_printf(adv->dev, "Unable to allocate CCB info "
589241492Sjhb		    "dmamap - error %d\n", error);
59055945Sgibbs		return (NULL);
59139217Sgibbs	}
59255945Sgibbs	adv->ccb_infos_allocated++;
59339217Sgibbs	return (cinfo);
59439217Sgibbs}
59539217Sgibbs
59639217Sgibbsstatic void
59739217Sgibbsadv_destroy_ccb_info(struct adv_softc *adv, struct adv_ccb_info *cinfo)
59839217Sgibbs{
599241492Sjhb
600241492Sjhb	callout_drain(&cinfo->timer);
60139217Sgibbs	bus_dmamap_destroy(adv->buffer_dmat, cinfo->dmamap);
60239217Sgibbs}
60339217Sgibbs
60439217Sgibbsvoid
60539217Sgibbsadv_timeout(void *arg)
60639217Sgibbs{
60739217Sgibbs	union ccb *ccb;
60839217Sgibbs	struct adv_softc *adv;
609241492Sjhb	struct adv_ccb_info *cinfo, *cinfo2;
61039217Sgibbs
61139217Sgibbs	ccb = (union ccb *)arg;
61239217Sgibbs	adv = (struct adv_softc *)xpt_path_sim(ccb->ccb_h.path)->softc;
61339217Sgibbs	cinfo = (struct adv_ccb_info *)ccb->ccb_h.ccb_cinfo_ptr;
614241492Sjhb	mtx_assert(&adv->lock, MA_OWNED);
61539217Sgibbs
61639217Sgibbs	xpt_print_path(ccb->ccb_h.path);
61739217Sgibbs	printf("Timed out\n");
61839217Sgibbs
61939217Sgibbs	/* Have we been taken care of already?? */
62039217Sgibbs	if (cinfo == NULL || cinfo->state == ACCB_FREE) {
62139217Sgibbs		return;
62239217Sgibbs	}
62339217Sgibbs
62439217Sgibbs	adv_stop_execution(adv);
62539217Sgibbs
62639217Sgibbs	if ((cinfo->state & ACCB_ABORT_QUEUED) == 0) {
62739217Sgibbs		struct ccb_hdr *ccb_h;
62839217Sgibbs
62939217Sgibbs		/*
63039217Sgibbs		 * In order to simplify the recovery process, we ask the XPT
63139217Sgibbs		 * layer to halt the queue of new transactions and we traverse
63239217Sgibbs		 * the list of pending CCBs and remove their timeouts. This
63339217Sgibbs		 * means that the driver attempts to clear only one error
63439217Sgibbs		 * condition at a time.  In general, timeouts that occur
63539217Sgibbs		 * close together are related anyway, so there is no benefit
63639217Sgibbs		 * in attempting to handle errors in parrallel.  Timeouts will
63739217Sgibbs		 * be reinstated when the recovery process ends.
63839217Sgibbs		 */
63955945Sgibbs		adv_set_state(adv, ADV_IN_TIMEOUT);
64039217Sgibbs
64139217Sgibbs		/* This CCB is the CCB representing our recovery actions */
64239217Sgibbs		cinfo->state |= ACCB_RECOVERY_CCB|ACCB_ABORT_QUEUED;
64339217Sgibbs
64439217Sgibbs		ccb_h = LIST_FIRST(&adv->pending_ccbs);
64539217Sgibbs		while (ccb_h != NULL) {
646241492Sjhb			cinfo2 = ccb_h->ccb_cinfo_ptr;
647241492Sjhb			callout_stop(&cinfo2->timer);
64839217Sgibbs			ccb_h = LIST_NEXT(ccb_h, sim_links.le);
64939217Sgibbs		}
65039217Sgibbs
65139217Sgibbs		/* XXX Should send a BDR */
65239217Sgibbs		/* Attempt an abort as our first tact */
65339217Sgibbs		xpt_print_path(ccb->ccb_h.path);
65439217Sgibbs		printf("Attempting abort\n");
65539217Sgibbs		adv_abort_ccb(adv, ccb->ccb_h.target_id,
65639217Sgibbs			      ccb->ccb_h.target_lun, ccb,
65739217Sgibbs			      CAM_CMD_TIMEOUT, /*queued_only*/FALSE);
658241492Sjhb		callout_reset(&cinfo->timer, 2 * hz, adv_timeout, ccb);
65939217Sgibbs	} else {
66039217Sgibbs		/* Our attempt to perform an abort failed, go for a reset */
66139217Sgibbs		xpt_print_path(ccb->ccb_h.path);
66239217Sgibbs		printf("Resetting bus\n");
66339217Sgibbs		ccb->ccb_h.status &= ~CAM_STATUS_MASK;
66439217Sgibbs		ccb->ccb_h.status |= CAM_CMD_TIMEOUT;
66555945Sgibbs		adv_reset_bus(adv, /*initiate_reset*/TRUE);
66639217Sgibbs	}
66739217Sgibbs	adv_start_execution(adv);
66839217Sgibbs}
66939217Sgibbs
67039217Sgibbsstruct adv_softc *
671241492Sjhbadv_alloc(device_t dev, struct resource *res, long offset)
67239217Sgibbs{
67359082Snyan	struct adv_softc *adv = device_get_softc(dev);
67439217Sgibbs
67539217Sgibbs	/*
67639217Sgibbs	 * Allocate a storage area for us
67739217Sgibbs	 */
67839217Sgibbs	LIST_INIT(&adv->pending_ccbs);
67939217Sgibbs	SLIST_INIT(&adv->free_ccb_infos);
68059082Snyan	adv->dev = dev;
681241492Sjhb	adv->res = res;
682241492Sjhb	adv->reg_off = offset;
683241492Sjhb	mtx_init(&adv->lock, "adv", NULL, MTX_DEF);
68439217Sgibbs
68539217Sgibbs	return(adv);
68639217Sgibbs}
68739217Sgibbs
68839217Sgibbsvoid
68939217Sgibbsadv_free(struct adv_softc *adv)
69039217Sgibbs{
69139217Sgibbs	switch (adv->init_level) {
69255945Sgibbs	case 6:
69339217Sgibbs	{
69439217Sgibbs		struct adv_ccb_info *cinfo;
69539217Sgibbs
69639217Sgibbs		while ((cinfo = SLIST_FIRST(&adv->free_ccb_infos)) != NULL) {
69739217Sgibbs			SLIST_REMOVE_HEAD(&adv->free_ccb_infos, links);
69840420Sgibbs			adv_destroy_ccb_info(adv, cinfo);
69939217Sgibbs		}
70039217Sgibbs
70139217Sgibbs		bus_dmamap_unload(adv->sense_dmat, adv->sense_dmamap);
70239217Sgibbs	}
70355945Sgibbs	case 5:
70439217Sgibbs		bus_dmamem_free(adv->sense_dmat, adv->sense_buffers,
70539217Sgibbs                                adv->sense_dmamap);
70655945Sgibbs	case 4:
70755945Sgibbs		bus_dma_tag_destroy(adv->sense_dmat);
70839217Sgibbs	case 3:
70955945Sgibbs		bus_dma_tag_destroy(adv->buffer_dmat);
71039217Sgibbs	case 2:
71155945Sgibbs		bus_dma_tag_destroy(adv->parent_dmat);
71239217Sgibbs	case 1:
71372147Sjhb		if (adv->ccb_infos != NULL)
71472147Sjhb			free(adv->ccb_infos, M_DEVBUF);
71539217Sgibbs	case 0:
716241492Sjhb		mtx_destroy(&adv->lock);
71739217Sgibbs		break;
71839217Sgibbs	}
71939217Sgibbs}
72039217Sgibbs
72139217Sgibbsint
72239217Sgibbsadv_init(struct adv_softc *adv)
72339217Sgibbs{
72439217Sgibbs	struct	  adv_eeprom_config eeprom_config;
72539217Sgibbs	int	  checksum, i;
72655945Sgibbs	int	  max_sync;
72739217Sgibbs	u_int16_t config_lsw;
72839217Sgibbs	u_int16_t config_msw;
72939217Sgibbs
730241492Sjhb	mtx_lock(&adv->lock);
73139217Sgibbs	adv_lib_init(adv);
73239217Sgibbs
73355945Sgibbs  	/*
73455945Sgibbs	 * Stop script execution.
73555945Sgibbs	 */
73655945Sgibbs	adv_write_lram_16(adv, ADV_HALTCODE_W, 0x00FE);
73755945Sgibbs	adv_stop_execution(adv);
73855945Sgibbs	if (adv_stop_chip(adv) == 0 || adv_is_chip_halted(adv) == 0) {
739241492Sjhb		mtx_unlock(&adv->lock);
740241492Sjhb		device_printf(adv->dev,
741241492Sjhb		    "Unable to halt adapter. Initialization failed\n");
74239217Sgibbs		return (1);
74339217Sgibbs	}
74439217Sgibbs	ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR);
74539217Sgibbs	if (ADV_INW(adv, ADV_REG_PROG_COUNTER) != ADV_MCODE_START_ADDR) {
746241492Sjhb		mtx_unlock(&adv->lock);
747241492Sjhb		device_printf(adv->dev,
748241492Sjhb		    "Unable to set program counter. Initialization failed\n");
74939217Sgibbs		return (1);
75039217Sgibbs	}
75139217Sgibbs
75239217Sgibbs	config_msw = ADV_INW(adv, ADV_CONFIG_MSW);
75339217Sgibbs	config_lsw = ADV_INW(adv, ADV_CONFIG_LSW);
75439217Sgibbs
75539217Sgibbs	if ((config_msw & ADV_CFG_MSW_CLR_MASK) != 0) {
75655945Sgibbs		config_msw &= ~ADV_CFG_MSW_CLR_MASK;
75739217Sgibbs		/*
75839217Sgibbs		 * XXX The Linux code flags this as an error,
75939217Sgibbs		 * but what should we report to the user???
76039217Sgibbs		 * It seems that clearing the config register
76139217Sgibbs		 * makes this error recoverable.
76239217Sgibbs		 */
76339217Sgibbs		ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw);
76439217Sgibbs	}
76539217Sgibbs
76639217Sgibbs	/* Suck in the configuration from the EEProm */
76739217Sgibbs	checksum = adv_get_eeprom_config(adv, &eeprom_config);
76839217Sgibbs
76939217Sgibbs	if (ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_AUTO_CONFIG) {
77039217Sgibbs		/*
77139217Sgibbs		 * XXX The Linux code sets a warning level for this
77239217Sgibbs		 * condition, yet nothing of meaning is printed to
77339217Sgibbs		 * the user.  What does this mean???
77439217Sgibbs		 */
77539217Sgibbs		if (adv->chip_version == 3) {
77655945Sgibbs			if (eeprom_config.cfg_lsw != config_lsw)
77755945Sgibbs				eeprom_config.cfg_lsw = config_lsw;
77839217Sgibbs			if (eeprom_config.cfg_msw != config_msw) {
77955945Sgibbs				eeprom_config.cfg_msw = config_msw;
78039217Sgibbs			}
78139217Sgibbs		}
78239217Sgibbs	}
78339217Sgibbs	if (checksum == eeprom_config.chksum) {
78455945Sgibbs
78539217Sgibbs		/* Range/Sanity checking */
78639217Sgibbs		if (eeprom_config.max_total_qng < ADV_MIN_TOTAL_QNG) {
78739217Sgibbs			eeprom_config.max_total_qng = ADV_MIN_TOTAL_QNG;
78839217Sgibbs		}
78939217Sgibbs		if (eeprom_config.max_total_qng > ADV_MAX_TOTAL_QNG) {
79039217Sgibbs			eeprom_config.max_total_qng = ADV_MAX_TOTAL_QNG;
79139217Sgibbs		}
79239217Sgibbs		if (eeprom_config.max_tag_qng > eeprom_config.max_total_qng) {
79339217Sgibbs			eeprom_config.max_tag_qng = eeprom_config.max_total_qng;
79439217Sgibbs		}
79539217Sgibbs		if (eeprom_config.max_tag_qng < ADV_MIN_TAG_Q_PER_DVC) {
79639217Sgibbs			eeprom_config.max_tag_qng = ADV_MIN_TAG_Q_PER_DVC;
79739217Sgibbs		}
79839217Sgibbs		adv->max_openings = eeprom_config.max_total_qng;
79939217Sgibbs		adv->user_disc_enable = eeprom_config.disc_enable;
80039217Sgibbs		adv->user_cmd_qng_enabled = eeprom_config.use_cmd_qng;
80139217Sgibbs		adv->isa_dma_speed = EEPROM_DMA_SPEED(eeprom_config);
80239217Sgibbs		adv->scsi_id = EEPROM_SCSIID(eeprom_config) & ADV_MAX_TID;
80339217Sgibbs		EEPROM_SET_SCSIID(eeprom_config, adv->scsi_id);
80439217Sgibbs		adv->control = eeprom_config.cntl;
80555945Sgibbs		for (i = 0; i <= ADV_MAX_TID; i++) {
80655945Sgibbs			u_int8_t sync_data;
80755945Sgibbs
80855945Sgibbs			if ((eeprom_config.init_sdtr & (0x1 << i)) == 0)
80955945Sgibbs				sync_data = 0;
81055945Sgibbs			else
81155945Sgibbs				sync_data = eeprom_config.sdtr_data[i];
81239217Sgibbs			adv_sdtr_to_period_offset(adv,
81355945Sgibbs						  sync_data,
81439217Sgibbs						  &adv->tinfo[i].user.period,
81539217Sgibbs						  &adv->tinfo[i].user.offset,
81639217Sgibbs						  i);
81755945Sgibbs		}
81855945Sgibbs		config_lsw = eeprom_config.cfg_lsw;
81955945Sgibbs		eeprom_config.cfg_msw = config_msw;
82039217Sgibbs	} else {
82139217Sgibbs		u_int8_t sync_data;
82239217Sgibbs
823241492Sjhb		device_printf(adv->dev, "Warning EEPROM Checksum mismatch. "
824241492Sjhb		       "Using default device parameters\n");
82539217Sgibbs
82639217Sgibbs		/* Set reasonable defaults since we can't read the EEPROM */
82739217Sgibbs		adv->isa_dma_speed = /*ADV_DEF_ISA_DMA_SPEED*/1;
82839217Sgibbs		adv->max_openings = ADV_DEF_MAX_TOTAL_QNG;
82939217Sgibbs		adv->disc_enable = TARGET_BIT_VECTOR_SET;
83039217Sgibbs		adv->user_disc_enable = TARGET_BIT_VECTOR_SET;
83139217Sgibbs		adv->cmd_qng_enabled = TARGET_BIT_VECTOR_SET;
83239217Sgibbs		adv->user_cmd_qng_enabled = TARGET_BIT_VECTOR_SET;
83339217Sgibbs		adv->scsi_id = 7;
83455945Sgibbs		adv->control = 0xFFFF;
83539217Sgibbs
83655945Sgibbs		if (adv->chip_version == ADV_CHIP_VER_PCI_ULTRA_3050)
83755945Sgibbs			/* Default to no Ultra to support the 3030 */
83855945Sgibbs			adv->control &= ~ADV_CNTL_SDTR_ENABLE_ULTRA;
83939217Sgibbs		sync_data = ADV_DEF_SDTR_OFFSET | (ADV_DEF_SDTR_INDEX << 4);
84055945Sgibbs		for (i = 0; i <= ADV_MAX_TID; i++) {
84139217Sgibbs			adv_sdtr_to_period_offset(adv, sync_data,
84239217Sgibbs						  &adv->tinfo[i].user.period,
84339217Sgibbs						  &adv->tinfo[i].user.offset,
84439217Sgibbs						  i);
84555945Sgibbs		}
84655945Sgibbs		config_lsw |= ADV_CFG_LSW_SCSI_PARITY_ON;
84739217Sgibbs	}
84855945Sgibbs	config_msw &= ~ADV_CFG_MSW_CLR_MASK;
84955945Sgibbs	config_lsw |= ADV_CFG_LSW_HOST_INT_ON;
85055945Sgibbs	if ((adv->type & (ADV_PCI|ADV_ULTRA)) == (ADV_PCI|ADV_ULTRA)
85155945Sgibbs	 && (adv->control & ADV_CNTL_SDTR_ENABLE_ULTRA) == 0)
85255945Sgibbs		/* 25ns or 10MHz */
85355945Sgibbs		max_sync = 25;
85455945Sgibbs	else
85555945Sgibbs		/* Unlimited */
85655945Sgibbs		max_sync = 0;
85755945Sgibbs	for (i = 0; i <= ADV_MAX_TID; i++) {
85855945Sgibbs		if (adv->tinfo[i].user.period < max_sync)
85955945Sgibbs			adv->tinfo[i].user.period = max_sync;
86055945Sgibbs	}
86139217Sgibbs
86255945Sgibbs	if (adv_test_external_lram(adv) == 0) {
86355945Sgibbs		if ((adv->type & (ADV_PCI|ADV_ULTRA)) == (ADV_PCI|ADV_ULTRA)) {
86455945Sgibbs			eeprom_config.max_total_qng =
86555945Sgibbs			    ADV_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
86655945Sgibbs			eeprom_config.max_tag_qng =
86755945Sgibbs			    ADV_MAX_PCI_ULTRA_INRAM_TAG_QNG;
86855945Sgibbs		} else {
86955945Sgibbs			eeprom_config.cfg_msw |= 0x0800;
87055945Sgibbs			config_msw |= 0x0800;
87155945Sgibbs			eeprom_config.max_total_qng =
87255945Sgibbs			     ADV_MAX_PCI_INRAM_TOTAL_QNG;
87355945Sgibbs			eeprom_config.max_tag_qng = ADV_MAX_INRAM_TAG_QNG;
87455945Sgibbs		}
87555945Sgibbs		adv->max_openings = eeprom_config.max_total_qng;
87655945Sgibbs	}
87755945Sgibbs	ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw);
87855945Sgibbs	ADV_OUTW(adv, ADV_CONFIG_LSW, config_lsw);
87955945Sgibbs#if 0
88055945Sgibbs	/*
88155945Sgibbs	 * Don't write the eeprom data back for now.
88255945Sgibbs	 * I'd rather not mess up the user's card.  We also don't
88355945Sgibbs	 * fully sanitize the eeprom settings above for the write-back
88455945Sgibbs	 * to be 100% correct.
88555945Sgibbs	 */
88639217Sgibbs	if (adv_set_eeprom_config(adv, &eeprom_config) != 0)
887241492Sjhb		device_printf(adv->dev,
888241492Sjhb		    "WARNING! Failure writing to EEPROM.\n");
88955945Sgibbs#endif
89039217Sgibbs
89139217Sgibbs	adv_set_chip_scsiid(adv, adv->scsi_id);
892241492Sjhb	if (adv_init_lram_and_mcode(adv)) {
893241492Sjhb		mtx_unlock(&adv->lock);
89439217Sgibbs		return (1);
895241492Sjhb	}
89639217Sgibbs
89739217Sgibbs	adv->disc_enable = adv->user_disc_enable;
89839217Sgibbs
89939217Sgibbs	adv_write_lram_8(adv, ADVV_DISC_ENABLE_B, adv->disc_enable);
90039217Sgibbs	for (i = 0; i <= ADV_MAX_TID; i++) {
90139217Sgibbs		/*
90239217Sgibbs		 * Start off in async mode.
90339217Sgibbs		 */
90439217Sgibbs		adv_set_syncrate(adv, /*struct cam_path */NULL,
90539217Sgibbs				 i, /*period*/0, /*offset*/0,
90639217Sgibbs				 ADV_TRANS_CUR);
90739217Sgibbs		/*
90839217Sgibbs		 * Enable the use of tagged commands on all targets.
90939217Sgibbs		 * This allows the kernel driver to make up it's own mind
91039217Sgibbs		 * as it sees fit to tag queue instead of having the
91139217Sgibbs		 * firmware try and second guess the tag_code settins.
91239217Sgibbs		 */
91339217Sgibbs		adv_write_lram_8(adv, ADVV_MAX_DVC_QNG_BEG + i,
91439217Sgibbs				 adv->max_openings);
91539217Sgibbs	}
91639217Sgibbs	adv_write_lram_8(adv, ADVV_USE_TAGGED_QNG_B, TARGET_BIT_VECTOR_SET);
91739217Sgibbs	adv_write_lram_8(adv, ADVV_CAN_TAGGED_QNG_B, TARGET_BIT_VECTOR_SET);
918241492Sjhb	device_printf(adv->dev,
919241492Sjhb	    "AdvanSys %s Host Adapter, SCSI ID %d, queue depth %d\n",
920241492Sjhb	    (adv->type & ADV_ULTRA) && (max_sync == 0)
921241492Sjhb	    ? "Ultra SCSI" : "SCSI",
922241492Sjhb	    adv->scsi_id, adv->max_openings);
923241492Sjhb	mtx_unlock(&adv->lock);
92439217Sgibbs	return (0);
92539217Sgibbs}
92639217Sgibbs
92739217Sgibbsvoid
92839217Sgibbsadv_intr(void *arg)
92939217Sgibbs{
93039217Sgibbs	struct	  adv_softc *adv;
931241492Sjhb
932241492Sjhb	adv = arg;
933241492Sjhb	mtx_lock(&adv->lock);
934241492Sjhb	adv_intr_locked(adv);
935241492Sjhb	mtx_unlock(&adv->lock);
936241492Sjhb}
937241492Sjhb
938241492Sjhbvoid
939241492Sjhbadv_intr_locked(struct adv_softc *adv)
940241492Sjhb{
94139217Sgibbs	u_int16_t chipstat;
94239217Sgibbs	u_int16_t saved_ram_addr;
94339217Sgibbs	u_int8_t  ctrl_reg;
94439217Sgibbs	u_int8_t  saved_ctrl_reg;
94539217Sgibbs	u_int8_t  host_flag;
94639217Sgibbs
947241492Sjhb	if (!dumping)
948241492Sjhb		mtx_assert(&adv->lock, MA_OWNED);
94955945Sgibbs	chipstat = ADV_INW(adv, ADV_CHIP_STATUS);
95055945Sgibbs
95155945Sgibbs	/* Is it for us? */
95255945Sgibbs	if ((chipstat & (ADV_CSW_INT_PENDING|ADV_CSW_SCSI_RESET_LATCH)) == 0)
95355945Sgibbs		return;
95455945Sgibbs
95539217Sgibbs	ctrl_reg = ADV_INB(adv, ADV_CHIP_CTRL);
95639217Sgibbs	saved_ctrl_reg = ctrl_reg & (~(ADV_CC_SCSI_RESET | ADV_CC_CHIP_RESET |
95739217Sgibbs				       ADV_CC_SINGLE_STEP | ADV_CC_DIAG |
95839217Sgibbs				       ADV_CC_TEST));
95939217Sgibbs
96055945Sgibbs	if ((chipstat & (ADV_CSW_SCSI_RESET_LATCH|ADV_CSW_SCSI_RESET_ACTIVE))) {
961241492Sjhb		device_printf(adv->dev, "Detected Bus Reset\n");
96255945Sgibbs		adv_reset_bus(adv, /*initiate_reset*/FALSE);
96355945Sgibbs		return;
96455945Sgibbs	}
96539217Sgibbs
96655945Sgibbs	if ((chipstat & ADV_CSW_INT_PENDING) != 0) {
96739217Sgibbs
96839217Sgibbs		saved_ram_addr = ADV_INW(adv, ADV_LRAM_ADDR);
96939217Sgibbs		host_flag = adv_read_lram_8(adv, ADVV_HOST_FLAG_B);
97039217Sgibbs		adv_write_lram_8(adv, ADVV_HOST_FLAG_B,
97139217Sgibbs				 host_flag | ADV_HOST_FLAG_IN_ISR);
97239217Sgibbs
97339217Sgibbs		adv_ack_interrupt(adv);
97439217Sgibbs
97555945Sgibbs		if ((chipstat & ADV_CSW_HALTED) != 0
97655945Sgibbs		 && (ctrl_reg & ADV_CC_SINGLE_STEP) != 0) {
97739217Sgibbs			adv_isr_chip_halted(adv);
97839217Sgibbs			saved_ctrl_reg &= ~ADV_CC_HALT;
97939217Sgibbs		} else {
98039217Sgibbs			adv_run_doneq(adv);
98139217Sgibbs		}
98239217Sgibbs		ADV_OUTW(adv, ADV_LRAM_ADDR, saved_ram_addr);
98339217Sgibbs#ifdef DIAGNOSTIC
98439217Sgibbs		if (ADV_INW(adv, ADV_LRAM_ADDR) != saved_ram_addr)
98539217Sgibbs			panic("adv_intr: Unable to set LRAM addr");
98639217Sgibbs#endif
98739217Sgibbs		adv_write_lram_8(adv, ADVV_HOST_FLAG_B, host_flag);
98839217Sgibbs	}
98939217Sgibbs
99039217Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, saved_ctrl_reg);
99139217Sgibbs}
99239217Sgibbs
993104094Sphkstatic void
99439217Sgibbsadv_run_doneq(struct adv_softc *adv)
99539217Sgibbs{
99639217Sgibbs	struct adv_q_done_info scsiq;
99739217Sgibbs	u_int		  doneq_head;
99839217Sgibbs	u_int		  done_qno;
99939217Sgibbs
100039217Sgibbs	doneq_head = adv_read_lram_16(adv, ADVV_DONE_Q_TAIL_W) & 0xFF;
100139217Sgibbs	done_qno = adv_read_lram_8(adv, ADV_QNO_TO_QADDR(doneq_head)
100239217Sgibbs				   + ADV_SCSIQ_B_FWD);
100339217Sgibbs	while (done_qno != ADV_QLINK_END) {
100439217Sgibbs		union ccb* ccb;
100555945Sgibbs		struct adv_ccb_info *cinfo;
100639217Sgibbs		u_int done_qaddr;
100739217Sgibbs		u_int sg_queue_cnt;
100839217Sgibbs		int   aborted;
100939217Sgibbs
101039217Sgibbs		done_qaddr = ADV_QNO_TO_QADDR(done_qno);
101139217Sgibbs
101239217Sgibbs		/* Pull status from this request */
101339217Sgibbs		sg_queue_cnt = adv_copy_lram_doneq(adv, done_qaddr, &scsiq,
101439217Sgibbs						   adv->max_dma_count);
101539217Sgibbs
101639217Sgibbs		/* Mark it as free */
101739217Sgibbs		adv_write_lram_8(adv, done_qaddr + ADV_SCSIQ_B_STATUS,
101839505Sgibbs				 scsiq.q_status & ~(QS_READY|QS_ABORTED));
101939217Sgibbs
102039217Sgibbs		/* Process request based on retrieved info */
102139217Sgibbs		if ((scsiq.cntl & QC_SG_HEAD) != 0) {
102239217Sgibbs			u_int i;
102339217Sgibbs
102439217Sgibbs			/*
102539217Sgibbs			 * S/G based request.  Free all of the queue
102639217Sgibbs			 * structures that contained S/G information.
102739217Sgibbs			 */
102839217Sgibbs			for (i = 0; i < sg_queue_cnt; i++) {
102939217Sgibbs				done_qno = adv_read_lram_8(adv, done_qaddr
103039217Sgibbs							   + ADV_SCSIQ_B_FWD);
103139217Sgibbs
103239217Sgibbs#ifdef DIAGNOSTIC
103339505Sgibbs				if (done_qno == ADV_QLINK_END) {
103439217Sgibbs					panic("adv_qdone: Corrupted SG "
103539217Sgibbs					      "list encountered");
103639217Sgibbs				}
103739217Sgibbs#endif
103839505Sgibbs				done_qaddr = ADV_QNO_TO_QADDR(done_qno);
103939505Sgibbs
104039217Sgibbs				/* Mark SG queue as free */
104139217Sgibbs				adv_write_lram_8(adv, done_qaddr
104239217Sgibbs						 + ADV_SCSIQ_B_STATUS, QS_FREE);
104339217Sgibbs			}
104439217Sgibbs		} else
104539217Sgibbs			sg_queue_cnt = 0;
104639217Sgibbs#ifdef DIAGNOSTIC
104739505Sgibbs		if (adv->cur_active < (sg_queue_cnt + 1))
104839217Sgibbs			panic("adv_qdone: Attempting to free more "
104939217Sgibbs			      "queues than are active");
105039217Sgibbs#endif
105139217Sgibbs		adv->cur_active -= sg_queue_cnt + 1;
105239217Sgibbs
105339217Sgibbs		aborted = (scsiq.q_status & QS_ABORTED) != 0;
105439217Sgibbs
105539217Sgibbs		if ((scsiq.q_status != QS_DONE)
105639217Sgibbs		 && (scsiq.q_status & QS_ABORTED) == 0)
105739217Sgibbs			panic("adv_qdone: completed scsiq with unknown status");
105839217Sgibbs
105939217Sgibbs		scsiq.remain_bytes += scsiq.extra_bytes;
106039217Sgibbs
106139217Sgibbs		if ((scsiq.d3.done_stat == QD_WITH_ERROR) &&
106239217Sgibbs		    (scsiq.d3.host_stat == QHSTA_M_DATA_OVER_RUN)) {
106339217Sgibbs			if ((scsiq.cntl & (QC_DATA_IN|QC_DATA_OUT)) == 0) {
106439217Sgibbs				scsiq.d3.done_stat = QD_NO_ERROR;
106539217Sgibbs				scsiq.d3.host_stat = QHSTA_NO_ERROR;
106639217Sgibbs			}
106739217Sgibbs		}
106839217Sgibbs
106955945Sgibbs		cinfo = &adv->ccb_infos[scsiq.d2.ccb_index];
107055945Sgibbs		ccb = cinfo->ccb;
107139217Sgibbs		ccb->csio.resid = scsiq.remain_bytes;
107255945Sgibbs		adv_done(adv, ccb,
107339217Sgibbs			 scsiq.d3.done_stat, scsiq.d3.host_stat,
107439217Sgibbs			 scsiq.d3.scsi_stat, scsiq.q_no);
107539217Sgibbs
107639217Sgibbs		doneq_head = done_qno;
107740027Sgibbs		done_qno = adv_read_lram_8(adv, done_qaddr + ADV_SCSIQ_B_FWD);
107839217Sgibbs	}
107939217Sgibbs	adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, doneq_head);
108039217Sgibbs}
108139217Sgibbs
108239217Sgibbs
108339217Sgibbsvoid
108439217Sgibbsadv_done(struct adv_softc *adv, union ccb *ccb, u_int done_stat,
108539217Sgibbs	 u_int host_stat, u_int scsi_status, u_int q_no)
108639217Sgibbs{
108739217Sgibbs	struct	   adv_ccb_info *cinfo;
108839217Sgibbs
1089241492Sjhb	if (!dumping)
1090241492Sjhb		mtx_assert(&adv->lock, MA_OWNED);
109139217Sgibbs	cinfo = (struct adv_ccb_info *)ccb->ccb_h.ccb_cinfo_ptr;
109245443Sgibbs	LIST_REMOVE(&ccb->ccb_h, sim_links.le);
1093241492Sjhb	callout_stop(&cinfo->timer);
109439217Sgibbs	if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
1095115343Sscottl		bus_dmasync_op_t op;
109639217Sgibbs
109739217Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
109839217Sgibbs			op = BUS_DMASYNC_POSTREAD;
109939217Sgibbs		else
110039217Sgibbs			op = BUS_DMASYNC_POSTWRITE;
110139217Sgibbs		bus_dmamap_sync(adv->buffer_dmat, cinfo->dmamap, op);
110239217Sgibbs		bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap);
110339217Sgibbs	}
110439217Sgibbs
110539217Sgibbs	switch (done_stat) {
110639217Sgibbs	case QD_NO_ERROR:
110745443Sgibbs		if (host_stat == QHSTA_NO_ERROR) {
110839217Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP;
110939217Sgibbs			break;
111039217Sgibbs		}
111145443Sgibbs		xpt_print_path(ccb->ccb_h.path);
111245443Sgibbs		printf("adv_done - queue done without error, "
111345443Sgibbs		       "but host status non-zero(%x)\n", host_stat);
111445443Sgibbs		/*FALLTHROUGH*/
111539217Sgibbs	case QD_WITH_ERROR:
111639217Sgibbs		switch (host_stat) {
111745443Sgibbs		case QHSTA_M_TARGET_STATUS_BUSY:
111845443Sgibbs		case QHSTA_M_BAD_QUEUE_FULL_OR_BUSY:
111945443Sgibbs			/*
112045443Sgibbs			 * Assume that if we were a tagged transaction
112145443Sgibbs			 * the target reported queue full.  Otherwise,
112245443Sgibbs			 * report busy.  The firmware really should just
112345443Sgibbs			 * pass the original status back up to us even
112445443Sgibbs			 * if it thinks the target was in error for
112545443Sgibbs			 * returning this status as no other transactions
112645443Sgibbs			 * from this initiator are in effect, but this
112745443Sgibbs			 * ignores multi-initiator setups and there is
112845443Sgibbs			 * evidence that the firmware gets its per-device
112945443Sgibbs			 * transaction counts screwed up occassionally.
113045443Sgibbs			 */
113145443Sgibbs			ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
113245443Sgibbs			if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0
113345443Sgibbs			 && host_stat != QHSTA_M_TARGET_STATUS_BUSY)
113445443Sgibbs				scsi_status = SCSI_STATUS_QUEUE_FULL;
113545443Sgibbs			else
113645443Sgibbs				scsi_status = SCSI_STATUS_BUSY;
113745443Sgibbs			adv_abort_ccb(adv, ccb->ccb_h.target_id,
113845443Sgibbs				      ccb->ccb_h.target_lun,
113945443Sgibbs				      /*ccb*/NULL, CAM_REQUEUE_REQ,
114045443Sgibbs				      /*queued_only*/TRUE);
114145443Sgibbs			/*FALLTHROUGH*/
114245443Sgibbs		case QHSTA_M_NO_AUTO_REQ_SENSE:
114339217Sgibbs		case QHSTA_NO_ERROR:
114439217Sgibbs			ccb->csio.scsi_status = scsi_status;
114539217Sgibbs			switch (scsi_status) {
114639217Sgibbs			case SCSI_STATUS_CHECK_COND:
114739217Sgibbs			case SCSI_STATUS_CMD_TERMINATED:
114839217Sgibbs				ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
114939217Sgibbs				/* Structure copy */
115039217Sgibbs				ccb->csio.sense_data =
115139217Sgibbs				    adv->sense_buffers[q_no - 1];
115239217Sgibbs				/* FALLTHROUGH */
115339217Sgibbs			case SCSI_STATUS_BUSY:
115439217Sgibbs			case SCSI_STATUS_RESERV_CONFLICT:
115539217Sgibbs			case SCSI_STATUS_QUEUE_FULL:
115639217Sgibbs			case SCSI_STATUS_COND_MET:
115739217Sgibbs			case SCSI_STATUS_INTERMED:
115839217Sgibbs			case SCSI_STATUS_INTERMED_COND_MET:
115939217Sgibbs				ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
116039217Sgibbs				break;
116139217Sgibbs			case SCSI_STATUS_OK:
116239217Sgibbs				ccb->ccb_h.status |= CAM_REQ_CMP;
116339217Sgibbs				break;
116439217Sgibbs			}
116539217Sgibbs			break;
116639217Sgibbs		case QHSTA_M_SEL_TIMEOUT:
116739217Sgibbs			ccb->ccb_h.status = CAM_SEL_TIMEOUT;
116839217Sgibbs			break;
116945443Sgibbs		case QHSTA_M_DATA_OVER_RUN:
117045443Sgibbs			ccb->ccb_h.status = CAM_DATA_RUN_ERR;
117145443Sgibbs			break;
117245443Sgibbs		case QHSTA_M_UNEXPECTED_BUS_FREE:
117345443Sgibbs			ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
117445443Sgibbs			break;
117545443Sgibbs		case QHSTA_M_BAD_BUS_PHASE_SEQ:
117645443Sgibbs			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
117745443Sgibbs			break;
117845443Sgibbs		case QHSTA_M_BAD_CMPL_STATUS_IN:
117945443Sgibbs			/* No command complete after a status message */
118045443Sgibbs			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
118145443Sgibbs			break;
118245443Sgibbs		case QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT:
118345443Sgibbs		case QHSTA_M_WTM_TIMEOUT:
118445443Sgibbs		case QHSTA_M_HUNG_REQ_SCSI_BUS_RESET:
118545443Sgibbs			/* The SCSI bus hung in a phase */
118645443Sgibbs			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
118755945Sgibbs			adv_reset_bus(adv, /*initiate_reset*/TRUE);
118845443Sgibbs			break;
118945846Sgibbs		case QHSTA_M_AUTO_REQ_SENSE_FAIL:
119045846Sgibbs			ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
119145846Sgibbs			break;
119245443Sgibbs		case QHSTA_D_QDONE_SG_LIST_CORRUPTED:
119345443Sgibbs		case QHSTA_D_ASC_DVC_ERROR_CODE_SET:
119445443Sgibbs		case QHSTA_D_HOST_ABORT_FAILED:
119545443Sgibbs		case QHSTA_D_EXE_SCSI_Q_FAILED:
119645443Sgibbs		case QHSTA_D_ASPI_NO_BUF_POOL:
119745443Sgibbs		case QHSTA_M_BAD_TAG_CODE:
119845443Sgibbs		case QHSTA_D_LRAM_CMP_ERROR:
119945443Sgibbs		case QHSTA_M_MICRO_CODE_ERROR_HALT:
120039217Sgibbs		default:
120145443Sgibbs			panic("%s: Unhandled Host status error %x",
1202241492Sjhb			    device_get_nameunit(adv->dev), host_stat);
120345443Sgibbs			/* NOTREACHED */
120439217Sgibbs		}
120539217Sgibbs		break;
120639217Sgibbs
120739217Sgibbs	case QD_ABORTED_BY_HOST:
120839217Sgibbs		/* Don't clobber any, more explicit, error codes we've set */
120939217Sgibbs		if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG)
121039217Sgibbs			ccb->ccb_h.status = CAM_REQ_ABORTED;
121139217Sgibbs		break;
121239217Sgibbs
121339217Sgibbs	default:
121440733Sgibbs		xpt_print_path(ccb->ccb_h.path);
121540733Sgibbs		printf("adv_done - queue done with unknown status %x:%x\n",
121640733Sgibbs		       done_stat, host_stat);
121739217Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
121839217Sgibbs		break;
121939217Sgibbs	}
122055945Sgibbs	adv_clear_state(adv, ccb);
122139217Sgibbs	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP
122239217Sgibbs	 && (ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
122339217Sgibbs		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
122439217Sgibbs		ccb->ccb_h.status |= CAM_DEV_QFRZN;
122539217Sgibbs	}
122639217Sgibbs	adv_free_ccb_info(adv, cinfo);
122755945Sgibbs	/*
122855945Sgibbs	 * Null this out so that we catch driver bugs that cause a
122955945Sgibbs	 * ccb to be completed twice.
123055945Sgibbs	 */
123155945Sgibbs	ccb->ccb_h.ccb_cinfo_ptr = NULL;
123239217Sgibbs	ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
123339217Sgibbs	xpt_done(ccb);
123439217Sgibbs}
123539217Sgibbs
123639217Sgibbs/*
123739217Sgibbs * Function to poll for command completion when
123839217Sgibbs * interrupts are disabled (crash dumps)
123939217Sgibbs */
124039217Sgibbsstatic void
124139217Sgibbsadv_poll(struct cam_sim *sim)
124239217Sgibbs{
1243241492Sjhb
1244241492Sjhb	adv_intr_locked(cam_sim_softc(sim));
124539217Sgibbs}
124639217Sgibbs
124739217Sgibbs/*
124839217Sgibbs * Attach all the sub-devices we can find
124939217Sgibbs */
125039217Sgibbsint
125139217Sgibbsadv_attach(adv)
125239217Sgibbs	struct adv_softc *adv;
125339217Sgibbs{
125439217Sgibbs	struct ccb_setasync csa;
125539217Sgibbs	struct cam_devq *devq;
125655945Sgibbs	int max_sg;
125739217Sgibbs
125839217Sgibbs	/*
125955945Sgibbs	 * Allocate an array of ccb mapping structures.  We put the
126055945Sgibbs	 * index of the ccb_info structure into the queue representing
126155945Sgibbs	 * a transaction and use it for mapping the queue to the
126255945Sgibbs	 * upper level SCSI transaction it represents.
126355945Sgibbs	 */
126455945Sgibbs	adv->ccb_infos = malloc(sizeof(*adv->ccb_infos) * adv->max_openings,
126555945Sgibbs				M_DEVBUF, M_NOWAIT);
126655945Sgibbs
126755945Sgibbs	if (adv->ccb_infos == NULL)
126860818Snyan		return (ENOMEM);
126955945Sgibbs
127055945Sgibbs	adv->init_level++;
127155945Sgibbs
127255945Sgibbs	/*
127339217Sgibbs	 * Create our DMA tags.  These tags define the kinds of device
127461686Salex	 * accessible memory allocations and memory mappings we will
127539217Sgibbs	 * need to perform during normal operation.
127639217Sgibbs	 *
127739217Sgibbs	 * Unless we need to further restrict the allocation, we rely
127839217Sgibbs	 * on the restrictions of the parent dmat, hence the common
127939217Sgibbs	 * use of MAXADDR and MAXSIZE.
128055945Sgibbs	 *
128155945Sgibbs	 * The ASC boards use chains of "queues" (the transactional
128255945Sgibbs	 * resources on the board) to represent long S/G lists.
128355945Sgibbs	 * The first queue represents the command and holds a
128455945Sgibbs	 * single address and data pair.  The queues that follow
128555945Sgibbs	 * can each hold ADV_SG_LIST_PER_Q entries.  Given the
128655945Sgibbs	 * total number of queues, we can express the largest
128755945Sgibbs	 * transaction we can map.  We reserve a few queues for
128855945Sgibbs	 * error recovery.  Take those into account as well.
128955945Sgibbs	 *
129055945Sgibbs	 * There is a way to take an interrupt to download the
129155945Sgibbs	 * next batch of S/G entries if there are more than 255
129255945Sgibbs	 * of them (the counter in the queue structure is a u_int8_t).
129355945Sgibbs	 * We don't use this feature, so limit the S/G list size
129455945Sgibbs	 * accordingly.
129539217Sgibbs	 */
129655945Sgibbs	max_sg = (adv->max_openings - ADV_MIN_FREE_Q - 1) * ADV_SG_LIST_PER_Q;
129755945Sgibbs	if (max_sg > 255)
129855945Sgibbs		max_sg = 255;
129939217Sgibbs
130039217Sgibbs	/* DMA tag for mapping buffers into device visible space. */
1301112782Smdodd	if (bus_dma_tag_create(
1302112782Smdodd			/* parent	*/ adv->parent_dmat,
1303112782Smdodd			/* alignment	*/ 1,
1304112782Smdodd			/* boundary	*/ 0,
1305112782Smdodd			/* lowaddr	*/ BUS_SPACE_MAXADDR,
1306112782Smdodd			/* highaddr	*/ BUS_SPACE_MAXADDR,
1307112782Smdodd			/* filter	*/ NULL,
1308112782Smdodd			/* filterarg	*/ NULL,
1309195534Sscottl			/* maxsize	*/ ADV_MAXPHYS,
1310112782Smdodd			/* nsegments	*/ max_sg,
1311112782Smdodd			/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
1312112782Smdodd			/* flags	*/ BUS_DMA_ALLOCNOW,
1313117126Sscottl			/* lockfunc	*/ busdma_lock_mutex,
1314241492Sjhb			/* lockarg	*/ &adv->lock,
1315112782Smdodd			&adv->buffer_dmat) != 0) {
131660818Snyan		return (ENXIO);
131739217Sgibbs	}
131839217Sgibbs	adv->init_level++;
131939217Sgibbs
132039217Sgibbs	/* DMA tag for our sense buffers */
1321112782Smdodd	if (bus_dma_tag_create(
1322112782Smdodd			/* parent	*/ adv->parent_dmat,
1323112782Smdodd			/* alignment	*/ 1,
1324112782Smdodd			/* boundary	*/ 0,
1325112782Smdodd			/* lowaddr	*/ BUS_SPACE_MAXADDR,
1326112782Smdodd			/* highaddr	*/ BUS_SPACE_MAXADDR,
1327112782Smdodd			/* filter	*/ NULL,
1328112782Smdodd			/* filterarg	*/ NULL,
1329112782Smdodd			/* maxsize	*/ sizeof(struct scsi_sense_data) *
1330112782Smdodd					   adv->max_openings,
1331112782Smdodd			/* nsegments	*/ 1,
1332112782Smdodd			/* maxsegsz	*/ BUS_SPACE_MAXSIZE_32BIT,
1333112782Smdodd			/* flags	*/ 0,
1334117126Sscottl			/* lockfunc	*/ busdma_lock_mutex,
1335241492Sjhb			/* lockarg	*/ &adv->lock,
1336112782Smdodd			&adv->sense_dmat) != 0) {
133760818Snyan		return (ENXIO);
133839217Sgibbs        }
133939217Sgibbs
134039217Sgibbs	adv->init_level++;
134139217Sgibbs
134239217Sgibbs	/* Allocation for our sense buffers */
134339217Sgibbs	if (bus_dmamem_alloc(adv->sense_dmat, (void **)&adv->sense_buffers,
134439217Sgibbs			     BUS_DMA_NOWAIT, &adv->sense_dmamap) != 0) {
134560818Snyan		return (ENOMEM);
134639217Sgibbs	}
134739217Sgibbs
134839217Sgibbs	adv->init_level++;
134939217Sgibbs
135039217Sgibbs	/* And permanently map them */
135139217Sgibbs	bus_dmamap_load(adv->sense_dmat, adv->sense_dmamap,
135239217Sgibbs       			adv->sense_buffers,
135339217Sgibbs			sizeof(struct scsi_sense_data)*adv->max_openings,
135439217Sgibbs			adv_map, &adv->sense_physbase, /*flags*/0);
135539217Sgibbs
135639217Sgibbs	adv->init_level++;
135739217Sgibbs
135839217Sgibbs	/*
135939217Sgibbs	 * Fire up the chip
136039217Sgibbs	 */
136139217Sgibbs	if (adv_start_chip(adv) != 1) {
1362241492Sjhb		device_printf(adv->dev,
1363241492Sjhb		    "Unable to start on board processor. Aborting.\n");
136460818Snyan		return (ENXIO);
136539217Sgibbs	}
136639217Sgibbs
136739217Sgibbs	/*
136839217Sgibbs	 * Create the device queue for our SIM.
136939217Sgibbs	 */
137039217Sgibbs	devq = cam_simq_alloc(adv->max_openings);
137139217Sgibbs	if (devq == NULL)
137260818Snyan		return (ENOMEM);
137339217Sgibbs
137439217Sgibbs	/*
137539217Sgibbs	 * Construct our SIM entry.
137639217Sgibbs	 */
1377241492Sjhb	adv->sim = cam_sim_alloc(adv_action, adv_poll, "adv", adv,
1378241492Sjhb	    device_get_unit(adv->dev), &adv->lock, 1, adv->max_openings, devq);
137939217Sgibbs	if (adv->sim == NULL)
138060818Snyan		return (ENOMEM);
138139217Sgibbs
138239217Sgibbs	/*
138339217Sgibbs	 * Register the bus.
138439217Sgibbs	 *
138539217Sgibbs	 * XXX Twin Channel EISA Cards???
138639217Sgibbs	 */
1387241492Sjhb	mtx_lock(&adv->lock);
1388170872Sscottl	if (xpt_bus_register(adv->sim, adv->dev, 0) != CAM_SUCCESS) {
138939217Sgibbs		cam_sim_free(adv->sim, /*free devq*/TRUE);
1390241492Sjhb		mtx_unlock(&adv->lock);
139160818Snyan		return (ENXIO);
139239217Sgibbs	}
139339217Sgibbs
139439217Sgibbs	if (xpt_create_path(&adv->path, /*periph*/NULL, cam_sim_path(adv->sim),
139539217Sgibbs			    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD)
139660818Snyan	    != CAM_REQ_CMP) {
139760818Snyan		xpt_bus_deregister(cam_sim_path(adv->sim));
139860818Snyan		cam_sim_free(adv->sim, /*free devq*/TRUE);
1399241492Sjhb		mtx_unlock(&adv->lock);
140060818Snyan		return (ENXIO);
140139217Sgibbs	}
140239217Sgibbs
140360818Snyan	xpt_setup_ccb(&csa.ccb_h, adv->path, /*priority*/5);
140460818Snyan	csa.ccb_h.func_code = XPT_SASYNC_CB;
140560818Snyan	csa.event_enable = AC_FOUND_DEVICE|AC_LOST_DEVICE;
140660818Snyan	csa.callback = advasync;
140760818Snyan	csa.callback_arg = adv;
140860818Snyan	xpt_action((union ccb *)&csa);
1409241492Sjhb	mtx_unlock(&adv->lock);
141039217Sgibbs	return (0);
141139217Sgibbs}
1412165102SmjacobMODULE_DEPEND(adv, cam, 1, 1, 1);
1413