advansys.c revision 55945
139217Sgibbs/*
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 *
3550477Speter * $FreeBSD: head/sys/dev/advansys/advansys.c 55945 2000-01-14 03:33:38Z gibbs $
3639217Sgibbs */
3739217Sgibbs/*
3839217Sgibbs * Ported from:
3939217Sgibbs * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
4039217Sgibbs *
4139217Sgibbs * Copyright (c) 1995-1997 Advanced System Products, Inc.
4239217Sgibbs * All Rights Reserved.
4339217Sgibbs *
4439217Sgibbs * Redistribution and use in source and binary forms, with or without
4539217Sgibbs * modification, are permitted provided that redistributions of source
4639217Sgibbs * code retain the above copyright notice and this comment without
4739217Sgibbs * modification.
4839217Sgibbs */
4939217Sgibbs
5039217Sgibbs#include <sys/param.h>
5139217Sgibbs#include <sys/systm.h>
5239217Sgibbs#include <sys/malloc.h>
5339217Sgibbs#include <sys/buf.h>
5439217Sgibbs#include <sys/kernel.h>
5539217Sgibbs
5639217Sgibbs#include <machine/bus_pio.h>
5739217Sgibbs#include <machine/bus.h>
5839217Sgibbs#include <machine/clock.h>
5939217Sgibbs
6039217Sgibbs#include <cam/cam.h>
6139217Sgibbs#include <cam/cam_ccb.h>
6239217Sgibbs#include <cam/cam_sim.h>
6339217Sgibbs#include <cam/cam_xpt_sim.h>
6439217Sgibbs#include <cam/cam_xpt_periph.h>
6539217Sgibbs#include <cam/cam_debug.h>
6639217Sgibbs
6739217Sgibbs#include <cam/scsi/scsi_all.h>
6839217Sgibbs#include <cam/scsi/scsi_message.h>
6939217Sgibbs
7039217Sgibbs#include <vm/vm.h>
7139217Sgibbs#include <vm/vm_param.h>
7239217Sgibbs#include <vm/pmap.h>
7339217Sgibbs
7439217Sgibbs#include <dev/advansys/advansys.h>
7539217Sgibbs
7639217Sgibbsu_long adv_unit;
7739217Sgibbs
7839217Sgibbsstatic void	adv_action(struct cam_sim *sim, union ccb *ccb);
7939217Sgibbsstatic void	adv_execute_ccb(void *arg, bus_dma_segment_t *dm_segs,
8039217Sgibbs				int nsegments, int error);
8139217Sgibbsstatic void	adv_poll(struct cam_sim *sim);
8239217Sgibbsstatic void	adv_run_doneq(struct adv_softc *adv);
8339217Sgibbsstatic struct adv_ccb_info *
8439217Sgibbs		adv_alloc_ccb_info(struct adv_softc *adv);
8539217Sgibbsstatic void	adv_destroy_ccb_info(struct adv_softc *adv,
8640420Sgibbs				     struct adv_ccb_info *cinfo);
8739217Sgibbsstatic __inline struct adv_ccb_info *
8839217Sgibbs		adv_get_ccb_info(struct adv_softc *adv);
8939217Sgibbsstatic __inline void adv_free_ccb_info(struct adv_softc *adv,
9039217Sgibbs				       struct adv_ccb_info *cinfo);
9155945Sgibbsstatic __inline void adv_set_state(struct adv_softc *adv, adv_state state);
9255945Sgibbsstatic __inline void adv_clear_state(struct adv_softc *adv, union ccb* ccb);
9355945Sgibbsstatic void adv_clear_state_really(struct adv_softc *adv, union ccb* ccb);
9439217Sgibbs
9539217Sgibbsstruct adv_softc *advsoftcs[NADV];   /* XXX Config should handle this */
9639217Sgibbs
9739217Sgibbsstatic __inline struct adv_ccb_info *
9839217Sgibbsadv_get_ccb_info(struct adv_softc *adv)
9939217Sgibbs{
10039217Sgibbs	struct adv_ccb_info *cinfo;
10139217Sgibbs	int opri;
10239217Sgibbs
10339217Sgibbs	opri = splcam();
10439217Sgibbs	if ((cinfo = SLIST_FIRST(&adv->free_ccb_infos)) != NULL) {
10539217Sgibbs		SLIST_REMOVE_HEAD(&adv->free_ccb_infos, links);
10639217Sgibbs	} else {
10739217Sgibbs		cinfo = adv_alloc_ccb_info(adv);
10839217Sgibbs	}
10939217Sgibbs	splx(opri);
11039217Sgibbs
11139217Sgibbs	return (cinfo);
11239217Sgibbs}
11339217Sgibbs
11439217Sgibbsstatic __inline void
11539217Sgibbsadv_free_ccb_info(struct adv_softc *adv, struct adv_ccb_info *cinfo)
11639217Sgibbs{
11739217Sgibbs	int opri;
11839217Sgibbs
11939217Sgibbs	opri = splcam();
12039217Sgibbs	cinfo->state = ACCB_FREE;
12139217Sgibbs	SLIST_INSERT_HEAD(&adv->free_ccb_infos, cinfo, links);
12239217Sgibbs	splx(opri);
12339217Sgibbs}
12439217Sgibbs
12555945Sgibbsstatic __inline void
12655945Sgibbsadv_set_state(struct adv_softc *adv, adv_state state)
12755945Sgibbs{
12855945Sgibbs	if (adv->state == 0)
12955945Sgibbs		xpt_freeze_simq(adv->sim, /*count*/1);
13055945Sgibbs	adv->state |= state;
13155945Sgibbs}
13255945Sgibbs
13355945Sgibbsstatic __inline void
13455945Sgibbsadv_clear_state(struct adv_softc *adv, union ccb* ccb)
13555945Sgibbs{
13655945Sgibbs	if (adv->state != 0)
13755945Sgibbs		adv_clear_state_really(adv, ccb);
13855945Sgibbs}
13955945Sgibbs
14055945Sgibbsstatic void
14155945Sgibbsadv_clear_state_really(struct adv_softc *adv, union ccb* ccb)
14255945Sgibbs{
14355945Sgibbs	if ((adv->state & ADV_BUSDMA_BLOCK_CLEARED) != 0)
14455945Sgibbs		adv->state &= ~(ADV_BUSDMA_BLOCK_CLEARED|ADV_BUSDMA_BLOCK);
14555945Sgibbs	if ((adv->state & ADV_RESOURCE_SHORTAGE) != 0) {
14655945Sgibbs		int openings;
14755945Sgibbs
14855945Sgibbs		openings = adv->max_openings - adv->cur_active - ADV_MIN_FREE_Q;
14955945Sgibbs		if (openings >= adv->openings_needed) {
15055945Sgibbs			adv->state &= ~ADV_RESOURCE_SHORTAGE;
15155945Sgibbs			adv->openings_needed = 0;
15255945Sgibbs		}
15355945Sgibbs	}
15455945Sgibbs
15555945Sgibbs	if ((adv->state & ADV_IN_TIMEOUT) != 0) {
15655945Sgibbs		struct adv_ccb_info *cinfo;
15755945Sgibbs
15855945Sgibbs		cinfo = (struct adv_ccb_info *)ccb->ccb_h.ccb_cinfo_ptr;
15955945Sgibbs		if ((cinfo->state & ACCB_RECOVERY_CCB) != 0) {
16055945Sgibbs			struct ccb_hdr *ccb_h;
16155945Sgibbs
16255945Sgibbs			/*
16355945Sgibbs			 * We now traverse our list of pending CCBs
16455945Sgibbs			 * and reinstate their timeouts.
16555945Sgibbs			 */
16655945Sgibbs			ccb_h = LIST_FIRST(&adv->pending_ccbs);
16755945Sgibbs			while (ccb_h != NULL) {
16855945Sgibbs				ccb_h->timeout_ch =
16955945Sgibbs				    timeout(adv_timeout, (caddr_t)ccb_h,
17055945Sgibbs					    (ccb_h->timeout * hz) / 1000);
17155945Sgibbs				ccb_h = LIST_NEXT(ccb_h, sim_links.le);
17255945Sgibbs			}
17355945Sgibbs			adv->state &= ~ADV_IN_TIMEOUT;
17455945Sgibbs			printf("%s: No longer in timeout\n", adv_name(adv));
17555945Sgibbs		}
17655945Sgibbs	}
17755945Sgibbs	if (adv->state == 0)
17855945Sgibbs		ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
17955945Sgibbs}
18055945Sgibbs
18139217Sgibbsvoid
18239217Sgibbsadv_map(void *arg, bus_dma_segment_t *segs, int nseg, int error)
18339217Sgibbs{
18439217Sgibbs	bus_addr_t* physaddr;
18539217Sgibbs
18639217Sgibbs	physaddr = (bus_addr_t*)arg;
18739217Sgibbs	*physaddr = segs->ds_addr;
18839217Sgibbs}
18939217Sgibbs
19039217Sgibbschar *
19139217Sgibbsadv_name(struct adv_softc *adv)
19239217Sgibbs{
19339217Sgibbs	static char name[10];
19439217Sgibbs
19541514Sarchie	snprintf(name, sizeof(name), "adv%d", adv->unit);
19639217Sgibbs	return (name);
19739217Sgibbs}
19839217Sgibbs
19939217Sgibbsstatic void
20039217Sgibbsadv_action(struct cam_sim *sim, union ccb *ccb)
20139217Sgibbs{
20239217Sgibbs	struct adv_softc *adv;
20339217Sgibbs
20439217Sgibbs	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("adv_action\n"));
20539217Sgibbs
20639217Sgibbs	adv = (struct adv_softc *)cam_sim_softc(sim);
20739217Sgibbs
20839217Sgibbs	switch (ccb->ccb_h.func_code) {
20939217Sgibbs	/* Common cases first */
21039217Sgibbs	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
21139217Sgibbs	{
21239217Sgibbs		struct	ccb_hdr *ccb_h;
21339217Sgibbs		struct	ccb_scsiio *csio;
21439217Sgibbs		struct	adv_ccb_info *cinfo;
21539217Sgibbs
21639217Sgibbs		ccb_h = &ccb->ccb_h;
21739217Sgibbs		csio = &ccb->csio;
21839217Sgibbs		cinfo = adv_get_ccb_info(adv);
21939217Sgibbs		if (cinfo == NULL)
22039217Sgibbs			panic("XXX Handle CCB info error!!!");
22139217Sgibbs
22239217Sgibbs		ccb_h->ccb_cinfo_ptr = cinfo;
22355945Sgibbs		cinfo->ccb = ccb;
22439217Sgibbs
22539217Sgibbs		/* Only use S/G if there is a transfer */
22639217Sgibbs		if ((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
22739217Sgibbs			if ((ccb_h->flags & CAM_SCATTER_VALID) == 0) {
22839217Sgibbs				/*
22939217Sgibbs				 * We've been given a pointer
23039217Sgibbs				 * to a single buffer
23139217Sgibbs				 */
23239217Sgibbs				if ((ccb_h->flags & CAM_DATA_PHYS) == 0) {
23339217Sgibbs					int s;
23439217Sgibbs					int error;
23539217Sgibbs
23639217Sgibbs					s = splsoftvm();
23739217Sgibbs					error =
23839217Sgibbs					    bus_dmamap_load(adv->buffer_dmat,
23939217Sgibbs							    cinfo->dmamap,
24039217Sgibbs							    csio->data_ptr,
24139217Sgibbs							    csio->dxfer_len,
24239217Sgibbs							    adv_execute_ccb,
24339217Sgibbs							    csio, /*flags*/0);
24439217Sgibbs					if (error == EINPROGRESS) {
24539217Sgibbs						/*
24639217Sgibbs						 * So as to maintain ordering,
24739217Sgibbs						 * freeze the controller queue
24839217Sgibbs						 * until our mapping is
24939217Sgibbs						 * returned.
25039217Sgibbs						 */
25155945Sgibbs						adv_set_state(adv,
25255945Sgibbs							      ADV_BUSDMA_BLOCK);
25339217Sgibbs					}
25439217Sgibbs					splx(s);
25539217Sgibbs				} else {
25639217Sgibbs					struct bus_dma_segment seg;
25739217Sgibbs
25839217Sgibbs					/* Pointer to physical buffer */
25939217Sgibbs					seg.ds_addr =
26039217Sgibbs					     (bus_addr_t)csio->data_ptr;
26139217Sgibbs					seg.ds_len = csio->dxfer_len;
26239217Sgibbs					adv_execute_ccb(csio, &seg, 1, 0);
26339217Sgibbs				}
26439217Sgibbs			} else {
26539217Sgibbs				struct bus_dma_segment *segs;
26639217Sgibbs				if ((ccb_h->flags & CAM_DATA_PHYS) != 0)
26739217Sgibbs					panic("adv_setup_data - Physical "
26839217Sgibbs					      "segment pointers unsupported");
26939217Sgibbs
27039217Sgibbs				if ((ccb_h->flags & CAM_SG_LIST_PHYS) == 0)
27139217Sgibbs					panic("adv_setup_data - Virtual "
27239217Sgibbs					      "segment addresses unsupported");
27339217Sgibbs
27439217Sgibbs				/* Just use the segments provided */
27539217Sgibbs				segs = (struct bus_dma_segment *)csio->data_ptr;
27639217Sgibbs				adv_execute_ccb(ccb, segs, csio->sglist_cnt, 0);
27739217Sgibbs			}
27839217Sgibbs		} else {
27939217Sgibbs			adv_execute_ccb(ccb, NULL, 0, 0);
28039217Sgibbs		}
28139217Sgibbs		break;
28239217Sgibbs	}
28339217Sgibbs	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
28439217Sgibbs	case XPT_TARGET_IO:	/* Execute target I/O request */
28539217Sgibbs	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
28639217Sgibbs	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/
28739217Sgibbs	case XPT_EN_LUN:		/* Enable LUN as a target */
28839217Sgibbs	case XPT_ABORT:			/* Abort the specified CCB */
28939217Sgibbs		/* XXX Implement */
29039217Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
29139217Sgibbs		xpt_done(ccb);
29239217Sgibbs		break;
29339217Sgibbs	case XPT_SET_TRAN_SETTINGS:
29439217Sgibbs	{
29539217Sgibbs		struct	 ccb_trans_settings *cts;
29639217Sgibbs		target_bit_vector targ_mask;
29746581Sken		struct adv_transinfo *tconf;
29839217Sgibbs		u_int	 update_type;
29939217Sgibbs		int	 s;
30039217Sgibbs
30139217Sgibbs		cts = &ccb->cts;
30239217Sgibbs		targ_mask = ADV_TID_TO_TARGET_MASK(cts->ccb_h.target_id);
30339217Sgibbs		update_type = 0;
30446581Sken
30546581Sken		/*
30646581Sken		 * The user must specify which type of settings he wishes
30746581Sken		 * to change.
30846581Sken		 */
30946581Sken		if (((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0)
31046581Sken		 && ((cts->flags & CCB_TRANS_USER_SETTINGS) == 0)) {
31146581Sken			tconf = &adv->tinfo[cts->ccb_h.target_id].current;
31239217Sgibbs			update_type |= ADV_TRANS_GOAL;
31346581Sken		} else if (((cts->flags & CCB_TRANS_USER_SETTINGS) != 0)
31446581Sken			&& ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) == 0)) {
31546581Sken			tconf = &adv->tinfo[cts->ccb_h.target_id].user;
31639217Sgibbs			update_type |= ADV_TRANS_USER;
31746581Sken		} else {
31846581Sken			ccb->ccb_h.status = CAM_REQ_INVALID;
31946581Sken			break;
32046581Sken		}
32139217Sgibbs
32239217Sgibbs		s = splcam();
32339217Sgibbs
32439217Sgibbs		if ((update_type & ADV_TRANS_GOAL) != 0) {
32539217Sgibbs			if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) {
32639217Sgibbs				if ((cts->flags & CCB_TRANS_DISC_ENB) != 0)
32739217Sgibbs					adv->disc_enable |= targ_mask;
32839217Sgibbs				else
32939217Sgibbs					adv->disc_enable &= ~targ_mask;
33039217Sgibbs				adv_write_lram_8(adv, ADVV_DISC_ENABLE_B,
33139217Sgibbs						 adv->disc_enable);
33239217Sgibbs			}
33339217Sgibbs
33439217Sgibbs			if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) {
33539217Sgibbs				if ((cts->flags & CCB_TRANS_TAG_ENB) != 0)
33639217Sgibbs					adv->cmd_qng_enabled |= targ_mask;
33739217Sgibbs				else
33839217Sgibbs					adv->cmd_qng_enabled &= ~targ_mask;
33939217Sgibbs			}
34039217Sgibbs		}
34139217Sgibbs
34239217Sgibbs		if ((update_type & ADV_TRANS_USER) != 0) {
34339217Sgibbs			if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) {
34439217Sgibbs				if ((cts->flags & CCB_TRANS_DISC_ENB) != 0)
34539217Sgibbs					adv->user_disc_enable |= targ_mask;
34639217Sgibbs				else
34739217Sgibbs					adv->user_disc_enable &= ~targ_mask;
34839217Sgibbs			}
34939217Sgibbs
35039217Sgibbs			if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) {
35139217Sgibbs				if ((cts->flags & CCB_TRANS_TAG_ENB) != 0)
35239217Sgibbs					adv->user_cmd_qng_enabled |= targ_mask;
35339217Sgibbs				else
35439217Sgibbs					adv->user_cmd_qng_enabled &= ~targ_mask;
35539217Sgibbs			}
35639217Sgibbs		}
35739217Sgibbs
35846581Sken		/*
35946581Sken		 * If the user specifies either the sync rate, or offset,
36046581Sken		 * but not both, the unspecified parameter defaults to its
36146581Sken		 * current value in transfer negotiations.
36246581Sken		 */
36346581Sken		if (((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0)
36446581Sken		 || ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)) {
36546581Sken			/*
36646581Sken			 * If the user provided a sync rate but no offset,
36746581Sken			 * use the current offset.
36846581Sken			 */
36939217Sgibbs			if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) == 0)
37046581Sken				cts->sync_offset = tconf->offset;
37139217Sgibbs
37246581Sken			/*
37346581Sken			 * If the user provided an offset but no sync rate,
37446581Sken			 * use the current sync rate.
37546581Sken			 */
37646581Sken			if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) == 0)
37746581Sken				cts->sync_period = tconf->period;
37846581Sken
37939217Sgibbs			adv_period_offset_to_sdtr(adv, &cts->sync_period,
38039217Sgibbs						  &cts->sync_offset,
38139217Sgibbs						  cts->ccb_h.target_id);
38239217Sgibbs
38339217Sgibbs			adv_set_syncrate(adv, /*struct cam_path */NULL,
38439217Sgibbs					 cts->ccb_h.target_id, cts->sync_period,
38539217Sgibbs					 cts->sync_offset, update_type);
38639217Sgibbs		}
38746581Sken
38839217Sgibbs		splx(s);
38939217Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
39039217Sgibbs		xpt_done(ccb);
39139217Sgibbs		break;
39239217Sgibbs	}
39339217Sgibbs	case XPT_GET_TRAN_SETTINGS:
39439217Sgibbs	/* Get default/user set transfer settings for the target */
39539217Sgibbs	{
39639217Sgibbs		struct ccb_trans_settings *cts;
39739217Sgibbs		struct adv_transinfo *tconf;
39839217Sgibbs		target_bit_vector target_mask;
39939217Sgibbs		int s;
40039217Sgibbs
40139217Sgibbs		cts = &ccb->cts;
40239217Sgibbs		target_mask = ADV_TID_TO_TARGET_MASK(cts->ccb_h.target_id);
40339217Sgibbs
40439217Sgibbs		cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB);
40539217Sgibbs
40639217Sgibbs		s = splcam();
40739217Sgibbs		if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) {
40839217Sgibbs			tconf = &adv->tinfo[cts->ccb_h.target_id].current;
40939217Sgibbs			if ((adv->disc_enable & target_mask) != 0)
41039217Sgibbs				cts->flags |= CCB_TRANS_DISC_ENB;
41139217Sgibbs			if ((adv->cmd_qng_enabled & target_mask) != 0)
41239217Sgibbs				cts->flags |= CCB_TRANS_TAG_ENB;
41339217Sgibbs		} else {
41439217Sgibbs			tconf = &adv->tinfo[cts->ccb_h.target_id].user;
41539217Sgibbs			if ((adv->user_disc_enable & target_mask) != 0)
41639217Sgibbs				cts->flags |= CCB_TRANS_DISC_ENB;
41739217Sgibbs			if ((adv->user_cmd_qng_enabled & target_mask) != 0)
41839217Sgibbs				cts->flags |= CCB_TRANS_TAG_ENB;
41939217Sgibbs		}
42039217Sgibbs
42139217Sgibbs		cts->sync_period = tconf->period;
42239217Sgibbs		cts->sync_offset = tconf->offset;
42339217Sgibbs		splx(s);
42439217Sgibbs
42539217Sgibbs		cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
42639217Sgibbs		cts->valid = CCB_TRANS_SYNC_RATE_VALID
42739217Sgibbs			   | CCB_TRANS_SYNC_OFFSET_VALID
42839217Sgibbs			   | CCB_TRANS_BUS_WIDTH_VALID
42939217Sgibbs			   | CCB_TRANS_DISC_VALID
43039217Sgibbs			   | CCB_TRANS_TQ_VALID;
43139217Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
43239217Sgibbs		xpt_done(ccb);
43339217Sgibbs		break;
43439217Sgibbs	}
43539217Sgibbs	case XPT_CALC_GEOMETRY:
43639217Sgibbs	{
43739217Sgibbs		struct	  ccb_calc_geometry *ccg;
43839217Sgibbs		u_int32_t size_mb;
43939217Sgibbs		u_int32_t secs_per_cylinder;
44039217Sgibbs		int	  extended;
44139217Sgibbs
44239217Sgibbs		ccg = &ccb->ccg;
44339217Sgibbs		size_mb = ccg->volume_size
44439217Sgibbs			/ ((1024L * 1024L) / ccg->block_size);
44539217Sgibbs		extended = (adv->control & ADV_CNTL_BIOS_GT_1GB) != 0;
44639217Sgibbs
44739217Sgibbs		if (size_mb > 1024 && extended) {
44839217Sgibbs			ccg->heads = 255;
44939217Sgibbs			ccg->secs_per_track = 63;
45039217Sgibbs		} else {
45139217Sgibbs			ccg->heads = 64;
45239217Sgibbs			ccg->secs_per_track = 32;
45339217Sgibbs		}
45439217Sgibbs		secs_per_cylinder = ccg->heads * ccg->secs_per_track;
45539217Sgibbs		ccg->cylinders = ccg->volume_size / secs_per_cylinder;
45639217Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
45739217Sgibbs		xpt_done(ccb);
45839217Sgibbs		break;
45939217Sgibbs	}
46039217Sgibbs	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
46139217Sgibbs	{
46239217Sgibbs		int s;
46339217Sgibbs
46439217Sgibbs		s = splcam();
46539217Sgibbs		adv_stop_execution(adv);
46655945Sgibbs		adv_reset_bus(adv, /*initiate_reset*/TRUE);
46739217Sgibbs		adv_start_execution(adv);
46839217Sgibbs		splx(s);
46939217Sgibbs
47039217Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
47139217Sgibbs		xpt_done(ccb);
47239217Sgibbs		break;
47339217Sgibbs	}
47439217Sgibbs	case XPT_TERM_IO:		/* Terminate the I/O process */
47539217Sgibbs		/* XXX Implement */
47639217Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
47739217Sgibbs		xpt_done(ccb);
47839217Sgibbs		break;
47939217Sgibbs	case XPT_PATH_INQ:		/* Path routing inquiry */
48039217Sgibbs	{
48139217Sgibbs		struct ccb_pathinq *cpi = &ccb->cpi;
48239217Sgibbs
48339217Sgibbs		cpi->version_num = 1; /* XXX??? */
48439217Sgibbs		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE;
48539217Sgibbs		cpi->target_sprt = 0;
48639217Sgibbs		cpi->hba_misc = 0;
48739217Sgibbs		cpi->hba_eng_cnt = 0;
48839217Sgibbs		cpi->max_target = 7;
48939217Sgibbs		cpi->max_lun = 7;
49039217Sgibbs		cpi->initiator_id = adv->scsi_id;
49139217Sgibbs		cpi->bus_id = cam_sim_bus(sim);
49246581Sken		cpi->base_transfer_speed = 3300;
49339217Sgibbs		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
49439217Sgibbs		strncpy(cpi->hba_vid, "Advansys", HBA_IDLEN);
49539217Sgibbs		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
49639217Sgibbs		cpi->unit_number = cam_sim_unit(sim);
49739217Sgibbs		cpi->ccb_h.status = CAM_REQ_CMP;
49839217Sgibbs		xpt_done(ccb);
49939217Sgibbs		break;
50039217Sgibbs	}
50139217Sgibbs	default:
50239217Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
50339217Sgibbs		xpt_done(ccb);
50439217Sgibbs		break;
50539217Sgibbs	}
50639217Sgibbs}
50739217Sgibbs
50839217Sgibbs/*
50939217Sgibbs * Currently, the output of bus_dmammap_load suits our needs just
51039217Sgibbs * fine, but should it change, we'd need to do something here.
51139217Sgibbs */
51239217Sgibbs#define adv_fixup_dmasegs(adv, dm_segs) (struct adv_sg_entry *)(dm_segs)
51339217Sgibbs
51439217Sgibbsstatic void
51539217Sgibbsadv_execute_ccb(void *arg, bus_dma_segment_t *dm_segs,
51639217Sgibbs		int nsegments, int error)
51739217Sgibbs{
51839217Sgibbs	struct	ccb_scsiio *csio;
51939217Sgibbs	struct	ccb_hdr *ccb_h;
52039217Sgibbs	struct	cam_sim *sim;
52139217Sgibbs        struct	adv_softc *adv;
52239217Sgibbs	struct	adv_ccb_info *cinfo;
52339217Sgibbs	struct	adv_scsi_q scsiq;
52439217Sgibbs	struct	adv_sg_head sghead;
52539217Sgibbs	int	s;
52639217Sgibbs
52739217Sgibbs	csio = (struct ccb_scsiio *)arg;
52839217Sgibbs	ccb_h = &csio->ccb_h;
52939217Sgibbs	sim = xpt_path_sim(ccb_h->path);
53039217Sgibbs	adv = (struct adv_softc *)cam_sim_softc(sim);
53139217Sgibbs	cinfo = (struct adv_ccb_info *)csio->ccb_h.ccb_cinfo_ptr;
53239217Sgibbs
53355945Sgibbs	/*
53455945Sgibbs	 * Setup our done routine to release the simq on
53555945Sgibbs	 * the next ccb that completes.
53655945Sgibbs	 */
53755945Sgibbs	if ((adv->state & ADV_BUSDMA_BLOCK) != 0)
53855945Sgibbs		adv->state |= ADV_BUSDMA_BLOCK_CLEARED;
53955945Sgibbs
54039217Sgibbs	if ((ccb_h->flags & CAM_CDB_POINTER) != 0) {
54139217Sgibbs		if ((ccb_h->flags & CAM_CDB_PHYS) == 0) {
54239217Sgibbs			/* XXX Need phystovirt!!!! */
54339217Sgibbs			/* How about pmap_kenter??? */
54439217Sgibbs			scsiq.cdbptr = csio->cdb_io.cdb_ptr;
54539217Sgibbs		} else {
54639217Sgibbs			scsiq.cdbptr = csio->cdb_io.cdb_ptr;
54739217Sgibbs		}
54839217Sgibbs	} else {
54939217Sgibbs		scsiq.cdbptr = csio->cdb_io.cdb_bytes;
55039217Sgibbs	}
55139217Sgibbs	/*
55239217Sgibbs	 * Build up the request
55339217Sgibbs	 */
55439217Sgibbs	scsiq.q1.status = 0;
55539217Sgibbs	scsiq.q1.q_no = 0;
55639217Sgibbs	scsiq.q1.cntl = 0;
55739217Sgibbs	scsiq.q1.sg_queue_cnt = 0;
55839217Sgibbs	scsiq.q1.target_id = ADV_TID_TO_TARGET_MASK(ccb_h->target_id);
55939217Sgibbs	scsiq.q1.target_lun = ccb_h->target_lun;
56039217Sgibbs	scsiq.q1.sense_len = csio->sense_len;
56139217Sgibbs	scsiq.q1.extra_bytes = 0;
56255945Sgibbs	scsiq.q2.ccb_index = cinfo - adv->ccb_infos;
56339217Sgibbs	scsiq.q2.target_ix = ADV_TIDLUN_TO_IX(ccb_h->target_id,
56439217Sgibbs					      ccb_h->target_lun);
56539217Sgibbs	scsiq.q2.flag = 0;
56639217Sgibbs	scsiq.q2.cdb_len = csio->cdb_len;
56739217Sgibbs	if ((ccb_h->flags & CAM_TAG_ACTION_VALID) != 0)
56839217Sgibbs		scsiq.q2.tag_code = csio->tag_action;
56939217Sgibbs	else
57039217Sgibbs		scsiq.q2.tag_code = 0;
57139217Sgibbs	scsiq.q2.vm_id = 0;
57239217Sgibbs
57339217Sgibbs	if (nsegments != 0) {
57439217Sgibbs		bus_dmasync_op_t op;
57539217Sgibbs
57639217Sgibbs		scsiq.q1.data_addr = dm_segs->ds_addr;
57739217Sgibbs                scsiq.q1.data_cnt = dm_segs->ds_len;
57839217Sgibbs		if (nsegments > 1) {
57939217Sgibbs			scsiq.q1.cntl |= QC_SG_HEAD;
58039217Sgibbs			sghead.entry_cnt
58139217Sgibbs			    = sghead.entry_to_copy
58239217Sgibbs			    = nsegments;
58339217Sgibbs			sghead.res = 0;
58439217Sgibbs			sghead.sg_list = adv_fixup_dmasegs(adv, dm_segs);
58539217Sgibbs			scsiq.sg_head = &sghead;
58639217Sgibbs		} else {
58739217Sgibbs			scsiq.sg_head = NULL;
58839217Sgibbs		}
58939217Sgibbs		if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN)
59039217Sgibbs			op = BUS_DMASYNC_PREREAD;
59139217Sgibbs		else
59239217Sgibbs			op = BUS_DMASYNC_PREWRITE;
59339217Sgibbs		bus_dmamap_sync(adv->buffer_dmat, cinfo->dmamap, op);
59439217Sgibbs	} else {
59539217Sgibbs		scsiq.q1.data_addr = 0;
59639217Sgibbs		scsiq.q1.data_cnt = 0;
59739217Sgibbs		scsiq.sg_head = NULL;
59839217Sgibbs	}
59939217Sgibbs
60040027Sgibbs	s = splcam();
60140027Sgibbs
60240027Sgibbs	/*
60340027Sgibbs	 * Last time we need to check if this SCB needs to
60440027Sgibbs	 * be aborted.
60540027Sgibbs	 */
60640027Sgibbs	if (ccb_h->status != CAM_REQ_INPROG) {
60755945Sgibbs		if (nsegments != 0)
60840027Sgibbs			bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap);
60955945Sgibbs		adv_clear_state(adv, (union ccb *)csio);
61040027Sgibbs		adv_free_ccb_info(adv, cinfo);
61140027Sgibbs		xpt_done((union ccb *)csio);
61240027Sgibbs		splx(s);
61340027Sgibbs		return;
61440027Sgibbs	}
61540027Sgibbs
61639217Sgibbs	if (adv_execute_scsi_queue(adv, &scsiq, csio->dxfer_len) != 0) {
61739217Sgibbs		/* Temporary resource shortage */
61855945Sgibbs		adv_set_state(adv, ADV_RESOURCE_SHORTAGE);
61955945Sgibbs		if (nsegments != 0)
62039217Sgibbs			bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap);
62155945Sgibbs		csio->ccb_h.status = CAM_REQUEUE_REQ;
62255945Sgibbs		adv_clear_state(adv, (union ccb *)csio);
62339217Sgibbs		adv_free_ccb_info(adv, cinfo);
62439217Sgibbs		xpt_done((union ccb *)csio);
62539217Sgibbs		splx(s);
62639217Sgibbs		return;
62739217Sgibbs	}
62840027Sgibbs	cinfo->state |= ACCB_ACTIVE;
62939217Sgibbs	ccb_h->status |= CAM_SIM_QUEUED;
63039217Sgibbs	LIST_INSERT_HEAD(&adv->pending_ccbs, ccb_h, sim_links.le);
63139217Sgibbs	/* Schedule our timeout */
63239217Sgibbs	ccb_h->timeout_ch =
63339217Sgibbs	    timeout(adv_timeout, csio, (ccb_h->timeout * hz)/1000);
63439217Sgibbs	splx(s);
63539217Sgibbs}
63639217Sgibbs
63739217Sgibbsstatic struct adv_ccb_info *
63839217Sgibbsadv_alloc_ccb_info(struct adv_softc *adv)
63939217Sgibbs{
64039217Sgibbs	int error;
64139217Sgibbs	struct adv_ccb_info *cinfo;
64239217Sgibbs
64355945Sgibbs	cinfo = &adv->ccb_infos[adv->ccb_infos_allocated];
64439217Sgibbs	cinfo->state = ACCB_FREE;
64539217Sgibbs	error = bus_dmamap_create(adv->buffer_dmat, /*flags*/0,
64639217Sgibbs				  &cinfo->dmamap);
64739217Sgibbs	if (error != 0) {
64839217Sgibbs		printf("%s: Unable to allocate CCB info "
64939217Sgibbs		       "dmamap - error %d\n", adv_name(adv), error);
65055945Sgibbs		return (NULL);
65139217Sgibbs	}
65255945Sgibbs	adv->ccb_infos_allocated++;
65339217Sgibbs	return (cinfo);
65439217Sgibbs}
65539217Sgibbs
65639217Sgibbsstatic void
65739217Sgibbsadv_destroy_ccb_info(struct adv_softc *adv, struct adv_ccb_info *cinfo)
65839217Sgibbs{
65939217Sgibbs	bus_dmamap_destroy(adv->buffer_dmat, cinfo->dmamap);
66039217Sgibbs}
66139217Sgibbs
66239217Sgibbsvoid
66339217Sgibbsadv_timeout(void *arg)
66439217Sgibbs{
66539217Sgibbs	int s;
66639217Sgibbs	union ccb *ccb;
66739217Sgibbs	struct adv_softc *adv;
66839217Sgibbs	struct adv_ccb_info *cinfo;
66939217Sgibbs
67039217Sgibbs	ccb = (union ccb *)arg;
67139217Sgibbs	adv = (struct adv_softc *)xpt_path_sim(ccb->ccb_h.path)->softc;
67239217Sgibbs	cinfo = (struct adv_ccb_info *)ccb->ccb_h.ccb_cinfo_ptr;
67339217Sgibbs
67439217Sgibbs	xpt_print_path(ccb->ccb_h.path);
67539217Sgibbs	printf("Timed out\n");
67639217Sgibbs
67739217Sgibbs	s = splcam();
67839217Sgibbs	/* Have we been taken care of already?? */
67939217Sgibbs	if (cinfo == NULL || cinfo->state == ACCB_FREE) {
68039217Sgibbs		splx(s);
68139217Sgibbs		return;
68239217Sgibbs	}
68339217Sgibbs
68439217Sgibbs	adv_stop_execution(adv);
68539217Sgibbs
68639217Sgibbs	if ((cinfo->state & ACCB_ABORT_QUEUED) == 0) {
68739217Sgibbs		struct ccb_hdr *ccb_h;
68839217Sgibbs
68939217Sgibbs		/*
69039217Sgibbs		 * In order to simplify the recovery process, we ask the XPT
69139217Sgibbs		 * layer to halt the queue of new transactions and we traverse
69239217Sgibbs		 * the list of pending CCBs and remove their timeouts. This
69339217Sgibbs		 * means that the driver attempts to clear only one error
69439217Sgibbs		 * condition at a time.  In general, timeouts that occur
69539217Sgibbs		 * close together are related anyway, so there is no benefit
69639217Sgibbs		 * in attempting to handle errors in parrallel.  Timeouts will
69739217Sgibbs		 * be reinstated when the recovery process ends.
69839217Sgibbs		 */
69955945Sgibbs		adv_set_state(adv, ADV_IN_TIMEOUT);
70039217Sgibbs
70139217Sgibbs		/* This CCB is the CCB representing our recovery actions */
70239217Sgibbs		cinfo->state |= ACCB_RECOVERY_CCB|ACCB_ABORT_QUEUED;
70339217Sgibbs
70439217Sgibbs		ccb_h = LIST_FIRST(&adv->pending_ccbs);
70539217Sgibbs		while (ccb_h != NULL) {
70639217Sgibbs			untimeout(adv_timeout, ccb_h, ccb_h->timeout_ch);
70739217Sgibbs			ccb_h = LIST_NEXT(ccb_h, sim_links.le);
70839217Sgibbs		}
70939217Sgibbs
71039217Sgibbs		/* XXX Should send a BDR */
71139217Sgibbs		/* Attempt an abort as our first tact */
71239217Sgibbs		xpt_print_path(ccb->ccb_h.path);
71339217Sgibbs		printf("Attempting abort\n");
71439217Sgibbs		adv_abort_ccb(adv, ccb->ccb_h.target_id,
71539217Sgibbs			      ccb->ccb_h.target_lun, ccb,
71639217Sgibbs			      CAM_CMD_TIMEOUT, /*queued_only*/FALSE);
71739217Sgibbs		ccb->ccb_h.timeout_ch =
71839217Sgibbs		    timeout(adv_timeout, ccb, 2 * hz);
71939217Sgibbs	} else {
72039217Sgibbs		/* Our attempt to perform an abort failed, go for a reset */
72139217Sgibbs		xpt_print_path(ccb->ccb_h.path);
72239217Sgibbs		printf("Resetting bus\n");
72339217Sgibbs		ccb->ccb_h.status &= ~CAM_STATUS_MASK;
72439217Sgibbs		ccb->ccb_h.status |= CAM_CMD_TIMEOUT;
72555945Sgibbs		adv_reset_bus(adv, /*initiate_reset*/TRUE);
72639217Sgibbs	}
72739217Sgibbs	adv_start_execution(adv);
72839217Sgibbs	splx(s);
72939217Sgibbs}
73039217Sgibbs
73139217Sgibbsstruct adv_softc *
73239217Sgibbsadv_alloc(int unit, bus_space_tag_t tag, bus_space_handle_t bsh)
73339217Sgibbs{
73439217Sgibbs	struct	 adv_softc *adv;
73539217Sgibbs
73639217Sgibbs	if (unit >= NADV) {
73739217Sgibbs		printf("adv: unit number (%d) too high\n", unit);
73839217Sgibbs		return NULL;
73939217Sgibbs	}
74039217Sgibbs
74139217Sgibbs	/*
74239217Sgibbs	 * Allocate a storage area for us
74339217Sgibbs	 */
74439217Sgibbs	if (advsoftcs[unit]) {
74539217Sgibbs		printf("adv%d: memory already allocated\n", unit);
74639217Sgibbs		return NULL;
74739217Sgibbs	}
74839217Sgibbs
74939217Sgibbs	adv = malloc(sizeof(struct adv_softc), M_DEVBUF, M_NOWAIT);
75039217Sgibbs	if (!adv) {
75139217Sgibbs		printf("adv%d: cannot malloc!\n", unit);
75239217Sgibbs		return NULL;
75339217Sgibbs	}
75439217Sgibbs	bzero(adv, sizeof(struct adv_softc));
75539217Sgibbs	LIST_INIT(&adv->pending_ccbs);
75639217Sgibbs	SLIST_INIT(&adv->free_ccb_infos);
75739217Sgibbs	advsoftcs[unit] = adv;
75839217Sgibbs	adv->unit = unit;
75939217Sgibbs	adv->tag = tag;
76039217Sgibbs	adv->bsh = bsh;
76139217Sgibbs
76239217Sgibbs	return(adv);
76339217Sgibbs}
76439217Sgibbs
76539217Sgibbsvoid
76639217Sgibbsadv_free(struct adv_softc *adv)
76739217Sgibbs{
76839217Sgibbs	switch (adv->init_level) {
76955945Sgibbs	case 6:
77039217Sgibbs	{
77139217Sgibbs		struct adv_ccb_info *cinfo;
77239217Sgibbs
77339217Sgibbs		while ((cinfo = SLIST_FIRST(&adv->free_ccb_infos)) != NULL) {
77439217Sgibbs			SLIST_REMOVE_HEAD(&adv->free_ccb_infos, links);
77540420Sgibbs			adv_destroy_ccb_info(adv, cinfo);
77639217Sgibbs		}
77739217Sgibbs
77839217Sgibbs		bus_dmamap_unload(adv->sense_dmat, adv->sense_dmamap);
77939217Sgibbs	}
78055945Sgibbs	case 5:
78139217Sgibbs		bus_dmamem_free(adv->sense_dmat, adv->sense_buffers,
78239217Sgibbs                                adv->sense_dmamap);
78355945Sgibbs	case 4:
78455945Sgibbs		bus_dma_tag_destroy(adv->sense_dmat);
78539217Sgibbs	case 3:
78655945Sgibbs		bus_dma_tag_destroy(adv->buffer_dmat);
78739217Sgibbs	case 2:
78855945Sgibbs		bus_dma_tag_destroy(adv->parent_dmat);
78939217Sgibbs	case 1:
79055945Sgibbs		free(adv->ccb_infos, M_DEVBUF);
79139217Sgibbs	case 0:
79239217Sgibbs		break;
79339217Sgibbs	}
79439217Sgibbs	free(adv, M_DEVBUF);
79539217Sgibbs}
79639217Sgibbs
79739217Sgibbsint
79839217Sgibbsadv_init(struct adv_softc *adv)
79939217Sgibbs{
80039217Sgibbs	struct	  adv_eeprom_config eeprom_config;
80139217Sgibbs	int	  checksum, i;
80255945Sgibbs	int	  max_sync;
80339217Sgibbs	u_int16_t config_lsw;
80439217Sgibbs	u_int16_t config_msw;
80539217Sgibbs
80639217Sgibbs	adv_lib_init(adv);
80739217Sgibbs
80855945Sgibbs  	/*
80955945Sgibbs	 * Stop script execution.
81055945Sgibbs	 */
81155945Sgibbs	adv_write_lram_16(adv, ADV_HALTCODE_W, 0x00FE);
81255945Sgibbs	adv_stop_execution(adv);
81355945Sgibbs	if (adv_stop_chip(adv) == 0 || adv_is_chip_halted(adv) == 0) {
81439217Sgibbs		printf("adv%d: Unable to halt adapter. Initialization"
81539217Sgibbs		       "failed\n", adv->unit);
81639217Sgibbs		return (1);
81739217Sgibbs	}
81839217Sgibbs	ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR);
81939217Sgibbs	if (ADV_INW(adv, ADV_REG_PROG_COUNTER) != ADV_MCODE_START_ADDR) {
82039217Sgibbs		printf("adv%d: Unable to set program counter. Initialization"
82139217Sgibbs		       "failed\n", adv->unit);
82239217Sgibbs		return (1);
82339217Sgibbs	}
82439217Sgibbs
82539217Sgibbs	config_msw = ADV_INW(adv, ADV_CONFIG_MSW);
82639217Sgibbs	config_lsw = ADV_INW(adv, ADV_CONFIG_LSW);
82739217Sgibbs
82839217Sgibbs	if ((config_msw & ADV_CFG_MSW_CLR_MASK) != 0) {
82955945Sgibbs		config_msw &= ~ADV_CFG_MSW_CLR_MASK;
83039217Sgibbs		/*
83139217Sgibbs		 * XXX The Linux code flags this as an error,
83239217Sgibbs		 * but what should we report to the user???
83339217Sgibbs		 * It seems that clearing the config register
83439217Sgibbs		 * makes this error recoverable.
83539217Sgibbs		 */
83639217Sgibbs		ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw);
83739217Sgibbs	}
83839217Sgibbs
83939217Sgibbs	/* Suck in the configuration from the EEProm */
84039217Sgibbs	checksum = adv_get_eeprom_config(adv, &eeprom_config);
84139217Sgibbs
84239217Sgibbs	if (ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_AUTO_CONFIG) {
84339217Sgibbs		/*
84439217Sgibbs		 * XXX The Linux code sets a warning level for this
84539217Sgibbs		 * condition, yet nothing of meaning is printed to
84639217Sgibbs		 * the user.  What does this mean???
84739217Sgibbs		 */
84839217Sgibbs		if (adv->chip_version == 3) {
84955945Sgibbs			if (eeprom_config.cfg_lsw != config_lsw)
85055945Sgibbs				eeprom_config.cfg_lsw = config_lsw;
85139217Sgibbs			if (eeprom_config.cfg_msw != config_msw) {
85255945Sgibbs				eeprom_config.cfg_msw = config_msw;
85339217Sgibbs			}
85439217Sgibbs		}
85539217Sgibbs	}
85639217Sgibbs	if (checksum == eeprom_config.chksum) {
85755945Sgibbs
85839217Sgibbs		/* Range/Sanity checking */
85939217Sgibbs		if (eeprom_config.max_total_qng < ADV_MIN_TOTAL_QNG) {
86039217Sgibbs			eeprom_config.max_total_qng = ADV_MIN_TOTAL_QNG;
86139217Sgibbs		}
86239217Sgibbs		if (eeprom_config.max_total_qng > ADV_MAX_TOTAL_QNG) {
86339217Sgibbs			eeprom_config.max_total_qng = ADV_MAX_TOTAL_QNG;
86439217Sgibbs		}
86539217Sgibbs		if (eeprom_config.max_tag_qng > eeprom_config.max_total_qng) {
86639217Sgibbs			eeprom_config.max_tag_qng = eeprom_config.max_total_qng;
86739217Sgibbs		}
86839217Sgibbs		if (eeprom_config.max_tag_qng < ADV_MIN_TAG_Q_PER_DVC) {
86939217Sgibbs			eeprom_config.max_tag_qng = ADV_MIN_TAG_Q_PER_DVC;
87039217Sgibbs		}
87139217Sgibbs		adv->max_openings = eeprom_config.max_total_qng;
87239217Sgibbs		adv->user_disc_enable = eeprom_config.disc_enable;
87339217Sgibbs		adv->user_cmd_qng_enabled = eeprom_config.use_cmd_qng;
87439217Sgibbs		adv->isa_dma_speed = EEPROM_DMA_SPEED(eeprom_config);
87539217Sgibbs		adv->scsi_id = EEPROM_SCSIID(eeprom_config) & ADV_MAX_TID;
87639217Sgibbs		EEPROM_SET_SCSIID(eeprom_config, adv->scsi_id);
87739217Sgibbs		adv->control = eeprom_config.cntl;
87855945Sgibbs		for (i = 0; i <= ADV_MAX_TID; i++) {
87955945Sgibbs			u_int8_t sync_data;
88055945Sgibbs
88155945Sgibbs			if ((eeprom_config.init_sdtr & (0x1 << i)) == 0)
88255945Sgibbs				sync_data = 0;
88355945Sgibbs			else
88455945Sgibbs				sync_data = eeprom_config.sdtr_data[i];
88539217Sgibbs			adv_sdtr_to_period_offset(adv,
88655945Sgibbs						  sync_data,
88739217Sgibbs						  &adv->tinfo[i].user.period,
88839217Sgibbs						  &adv->tinfo[i].user.offset,
88939217Sgibbs						  i);
89055945Sgibbs		}
89155945Sgibbs		config_lsw = eeprom_config.cfg_lsw;
89255945Sgibbs		eeprom_config.cfg_msw = config_msw;
89339217Sgibbs	} else {
89439217Sgibbs		u_int8_t sync_data;
89539217Sgibbs
89639217Sgibbs		printf("adv%d: Warning EEPROM Checksum mismatch. "
89739217Sgibbs		       "Using default device parameters\n", adv->unit);
89839217Sgibbs
89939217Sgibbs		/* Set reasonable defaults since we can't read the EEPROM */
90039217Sgibbs		adv->isa_dma_speed = /*ADV_DEF_ISA_DMA_SPEED*/1;
90139217Sgibbs		adv->max_openings = ADV_DEF_MAX_TOTAL_QNG;
90239217Sgibbs		adv->disc_enable = TARGET_BIT_VECTOR_SET;
90339217Sgibbs		adv->user_disc_enable = TARGET_BIT_VECTOR_SET;
90439217Sgibbs		adv->cmd_qng_enabled = TARGET_BIT_VECTOR_SET;
90539217Sgibbs		adv->user_cmd_qng_enabled = TARGET_BIT_VECTOR_SET;
90639217Sgibbs		adv->scsi_id = 7;
90755945Sgibbs		adv->control = 0xFFFF;
90839217Sgibbs
90955945Sgibbs		if (adv->chip_version == ADV_CHIP_VER_PCI_ULTRA_3050)
91055945Sgibbs			/* Default to no Ultra to support the 3030 */
91155945Sgibbs			adv->control &= ~ADV_CNTL_SDTR_ENABLE_ULTRA;
91239217Sgibbs		sync_data = ADV_DEF_SDTR_OFFSET | (ADV_DEF_SDTR_INDEX << 4);
91355945Sgibbs		for (i = 0; i <= ADV_MAX_TID; i++) {
91439217Sgibbs			adv_sdtr_to_period_offset(adv, sync_data,
91539217Sgibbs						  &adv->tinfo[i].user.period,
91639217Sgibbs						  &adv->tinfo[i].user.offset,
91739217Sgibbs						  i);
91855945Sgibbs		}
91955945Sgibbs		config_lsw |= ADV_CFG_LSW_SCSI_PARITY_ON;
92039217Sgibbs	}
92155945Sgibbs	config_msw &= ~ADV_CFG_MSW_CLR_MASK;
92255945Sgibbs	config_lsw |= ADV_CFG_LSW_HOST_INT_ON;
92355945Sgibbs	if ((adv->type & (ADV_PCI|ADV_ULTRA)) == (ADV_PCI|ADV_ULTRA)
92455945Sgibbs	 && (adv->control & ADV_CNTL_SDTR_ENABLE_ULTRA) == 0)
92555945Sgibbs		/* 25ns or 10MHz */
92655945Sgibbs		max_sync = 25;
92755945Sgibbs	else
92855945Sgibbs		/* Unlimited */
92955945Sgibbs		max_sync = 0;
93055945Sgibbs	for (i = 0; i <= ADV_MAX_TID; i++) {
93155945Sgibbs		if (adv->tinfo[i].user.period < max_sync)
93255945Sgibbs			adv->tinfo[i].user.period = max_sync;
93355945Sgibbs	}
93439217Sgibbs
93555945Sgibbs	if (adv_test_external_lram(adv) == 0) {
93655945Sgibbs		printf("No external RAM\n");
93755945Sgibbs		if ((adv->type & (ADV_PCI|ADV_ULTRA)) == (ADV_PCI|ADV_ULTRA)) {
93855945Sgibbs			eeprom_config.max_total_qng =
93955945Sgibbs			    ADV_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
94055945Sgibbs			eeprom_config.max_tag_qng =
94155945Sgibbs			    ADV_MAX_PCI_ULTRA_INRAM_TAG_QNG;
94255945Sgibbs		} else {
94355945Sgibbs			eeprom_config.cfg_msw |= 0x0800;
94455945Sgibbs			config_msw |= 0x0800;
94555945Sgibbs			eeprom_config.max_total_qng =
94655945Sgibbs			     ADV_MAX_PCI_INRAM_TOTAL_QNG;
94755945Sgibbs			eeprom_config.max_tag_qng = ADV_MAX_INRAM_TAG_QNG;
94855945Sgibbs		}
94955945Sgibbs		adv->max_openings = eeprom_config.max_total_qng;
95055945Sgibbs	}
95155945Sgibbs	ADV_OUTW(adv, ADV_CONFIG_MSW, config_msw);
95255945Sgibbs	ADV_OUTW(adv, ADV_CONFIG_LSW, config_lsw);
95355945Sgibbs#if 0
95455945Sgibbs	/*
95555945Sgibbs	 * Don't write the eeprom data back for now.
95655945Sgibbs	 * I'd rather not mess up the user's card.  We also don't
95755945Sgibbs	 * fully sanitize the eeprom settings above for the write-back
95855945Sgibbs	 * to be 100% correct.
95955945Sgibbs	 */
96039217Sgibbs	if (adv_set_eeprom_config(adv, &eeprom_config) != 0)
96139217Sgibbs		printf("%s: WARNING! Failure writing to EEPROM.\n",
96239217Sgibbs		       adv_name(adv));
96355945Sgibbs#endif
96439217Sgibbs
96539217Sgibbs	adv_set_chip_scsiid(adv, adv->scsi_id);
96639217Sgibbs	if (adv_init_lram_and_mcode(adv))
96739217Sgibbs		return (1);
96839217Sgibbs
96939217Sgibbs	adv->disc_enable = adv->user_disc_enable;
97039217Sgibbs
97139217Sgibbs	adv_write_lram_8(adv, ADVV_DISC_ENABLE_B, adv->disc_enable);
97239217Sgibbs	for (i = 0; i <= ADV_MAX_TID; i++) {
97339217Sgibbs		/*
97439217Sgibbs		 * Start off in async mode.
97539217Sgibbs		 */
97639217Sgibbs		adv_set_syncrate(adv, /*struct cam_path */NULL,
97739217Sgibbs				 i, /*period*/0, /*offset*/0,
97839217Sgibbs				 ADV_TRANS_CUR);
97939217Sgibbs		/*
98039217Sgibbs		 * Enable the use of tagged commands on all targets.
98139217Sgibbs		 * This allows the kernel driver to make up it's own mind
98239217Sgibbs		 * as it sees fit to tag queue instead of having the
98339217Sgibbs		 * firmware try and second guess the tag_code settins.
98439217Sgibbs		 */
98539217Sgibbs		adv_write_lram_8(adv, ADVV_MAX_DVC_QNG_BEG + i,
98639217Sgibbs				 adv->max_openings);
98739217Sgibbs	}
98839217Sgibbs	adv_write_lram_8(adv, ADVV_USE_TAGGED_QNG_B, TARGET_BIT_VECTOR_SET);
98939217Sgibbs	adv_write_lram_8(adv, ADVV_CAN_TAGGED_QNG_B, TARGET_BIT_VECTOR_SET);
99039217Sgibbs	printf("adv%d: AdvanSys %s Host Adapter, SCSI ID %d, queue depth %d\n",
99155945Sgibbs	       adv->unit, (adv->type & ADV_ULTRA) && (max_sync == 0)
99255945Sgibbs			  ? "Ultra SCSI" : "SCSI",
99339217Sgibbs	       adv->scsi_id, adv->max_openings);
99439217Sgibbs	return (0);
99539217Sgibbs}
99639217Sgibbs
99739217Sgibbsvoid
99839217Sgibbsadv_intr(void *arg)
99939217Sgibbs{
100039217Sgibbs	struct	  adv_softc *adv;
100139217Sgibbs	u_int16_t chipstat;
100239217Sgibbs	u_int16_t saved_ram_addr;
100339217Sgibbs	u_int8_t  ctrl_reg;
100439217Sgibbs	u_int8_t  saved_ctrl_reg;
100539217Sgibbs	u_int8_t  host_flag;
100639217Sgibbs
100739217Sgibbs	adv = (struct adv_softc *)arg;
100839217Sgibbs
100955945Sgibbs	chipstat = ADV_INW(adv, ADV_CHIP_STATUS);
101055945Sgibbs
101155945Sgibbs	/* Is it for us? */
101255945Sgibbs	if ((chipstat & (ADV_CSW_INT_PENDING|ADV_CSW_SCSI_RESET_LATCH)) == 0)
101355945Sgibbs		return;
101455945Sgibbs
101539217Sgibbs	ctrl_reg = ADV_INB(adv, ADV_CHIP_CTRL);
101639217Sgibbs	saved_ctrl_reg = ctrl_reg & (~(ADV_CC_SCSI_RESET | ADV_CC_CHIP_RESET |
101739217Sgibbs				       ADV_CC_SINGLE_STEP | ADV_CC_DIAG |
101839217Sgibbs				       ADV_CC_TEST));
101939217Sgibbs
102055945Sgibbs	if ((chipstat & (ADV_CSW_SCSI_RESET_LATCH|ADV_CSW_SCSI_RESET_ACTIVE))) {
102155945Sgibbs		printf("Detected Bus Reset\n");
102255945Sgibbs		adv_reset_bus(adv, /*initiate_reset*/FALSE);
102355945Sgibbs		return;
102455945Sgibbs	}
102539217Sgibbs
102655945Sgibbs	if ((chipstat & ADV_CSW_INT_PENDING) != 0) {
102739217Sgibbs
102839217Sgibbs		saved_ram_addr = ADV_INW(adv, ADV_LRAM_ADDR);
102939217Sgibbs		host_flag = adv_read_lram_8(adv, ADVV_HOST_FLAG_B);
103039217Sgibbs		adv_write_lram_8(adv, ADVV_HOST_FLAG_B,
103139217Sgibbs				 host_flag | ADV_HOST_FLAG_IN_ISR);
103239217Sgibbs
103339217Sgibbs		adv_ack_interrupt(adv);
103439217Sgibbs
103555945Sgibbs		if ((chipstat & ADV_CSW_HALTED) != 0
103655945Sgibbs		 && (ctrl_reg & ADV_CC_SINGLE_STEP) != 0) {
103739217Sgibbs			adv_isr_chip_halted(adv);
103839217Sgibbs			saved_ctrl_reg &= ~ADV_CC_HALT;
103939217Sgibbs		} else {
104039217Sgibbs			adv_run_doneq(adv);
104139217Sgibbs		}
104239217Sgibbs		ADV_OUTW(adv, ADV_LRAM_ADDR, saved_ram_addr);
104339217Sgibbs#ifdef DIAGNOSTIC
104439217Sgibbs		if (ADV_INW(adv, ADV_LRAM_ADDR) != saved_ram_addr)
104539217Sgibbs			panic("adv_intr: Unable to set LRAM addr");
104639217Sgibbs#endif
104739217Sgibbs		adv_write_lram_8(adv, ADVV_HOST_FLAG_B, host_flag);
104839217Sgibbs	}
104939217Sgibbs
105039217Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, saved_ctrl_reg);
105139217Sgibbs}
105239217Sgibbs
105339217Sgibbsvoid
105439217Sgibbsadv_run_doneq(struct adv_softc *adv)
105539217Sgibbs{
105639217Sgibbs	struct adv_q_done_info scsiq;
105739217Sgibbs	u_int		  doneq_head;
105839217Sgibbs	u_int		  done_qno;
105939217Sgibbs
106039217Sgibbs	doneq_head = adv_read_lram_16(adv, ADVV_DONE_Q_TAIL_W) & 0xFF;
106139217Sgibbs	done_qno = adv_read_lram_8(adv, ADV_QNO_TO_QADDR(doneq_head)
106239217Sgibbs				   + ADV_SCSIQ_B_FWD);
106339217Sgibbs	while (done_qno != ADV_QLINK_END) {
106439217Sgibbs		union ccb* ccb;
106555945Sgibbs		struct adv_ccb_info *cinfo;
106639217Sgibbs		u_int done_qaddr;
106739217Sgibbs		u_int sg_queue_cnt;
106839217Sgibbs		int   aborted;
106939217Sgibbs
107039217Sgibbs		done_qaddr = ADV_QNO_TO_QADDR(done_qno);
107139217Sgibbs
107239217Sgibbs		/* Pull status from this request */
107339217Sgibbs		sg_queue_cnt = adv_copy_lram_doneq(adv, done_qaddr, &scsiq,
107439217Sgibbs						   adv->max_dma_count);
107539217Sgibbs
107639217Sgibbs		/* Mark it as free */
107739217Sgibbs		adv_write_lram_8(adv, done_qaddr + ADV_SCSIQ_B_STATUS,
107839505Sgibbs				 scsiq.q_status & ~(QS_READY|QS_ABORTED));
107939217Sgibbs
108039217Sgibbs		/* Process request based on retrieved info */
108139217Sgibbs		if ((scsiq.cntl & QC_SG_HEAD) != 0) {
108239217Sgibbs			u_int i;
108339217Sgibbs
108439217Sgibbs			/*
108539217Sgibbs			 * S/G based request.  Free all of the queue
108639217Sgibbs			 * structures that contained S/G information.
108739217Sgibbs			 */
108839217Sgibbs			for (i = 0; i < sg_queue_cnt; i++) {
108939217Sgibbs				done_qno = adv_read_lram_8(adv, done_qaddr
109039217Sgibbs							   + ADV_SCSIQ_B_FWD);
109139217Sgibbs
109239217Sgibbs#ifdef DIAGNOSTIC
109339505Sgibbs				if (done_qno == ADV_QLINK_END) {
109439217Sgibbs					panic("adv_qdone: Corrupted SG "
109539217Sgibbs					      "list encountered");
109639217Sgibbs				}
109739217Sgibbs#endif
109839505Sgibbs				done_qaddr = ADV_QNO_TO_QADDR(done_qno);
109939505Sgibbs
110039217Sgibbs				/* Mark SG queue as free */
110139217Sgibbs				adv_write_lram_8(adv, done_qaddr
110239217Sgibbs						 + ADV_SCSIQ_B_STATUS, QS_FREE);
110339217Sgibbs			}
110439217Sgibbs		} else
110539217Sgibbs			sg_queue_cnt = 0;
110639217Sgibbs#ifdef DIAGNOSTIC
110739505Sgibbs		if (adv->cur_active < (sg_queue_cnt + 1))
110839217Sgibbs			panic("adv_qdone: Attempting to free more "
110939217Sgibbs			      "queues than are active");
111039217Sgibbs#endif
111139217Sgibbs		adv->cur_active -= sg_queue_cnt + 1;
111239217Sgibbs
111339217Sgibbs		aborted = (scsiq.q_status & QS_ABORTED) != 0;
111439217Sgibbs
111539217Sgibbs		if ((scsiq.q_status != QS_DONE)
111639217Sgibbs		 && (scsiq.q_status & QS_ABORTED) == 0)
111739217Sgibbs			panic("adv_qdone: completed scsiq with unknown status");
111839217Sgibbs
111939217Sgibbs		scsiq.remain_bytes += scsiq.extra_bytes;
112039217Sgibbs
112139217Sgibbs		if ((scsiq.d3.done_stat == QD_WITH_ERROR) &&
112239217Sgibbs		    (scsiq.d3.host_stat == QHSTA_M_DATA_OVER_RUN)) {
112339217Sgibbs			if ((scsiq.cntl & (QC_DATA_IN|QC_DATA_OUT)) == 0) {
112439217Sgibbs				scsiq.d3.done_stat = QD_NO_ERROR;
112539217Sgibbs				scsiq.d3.host_stat = QHSTA_NO_ERROR;
112639217Sgibbs			}
112739217Sgibbs		}
112839217Sgibbs
112955945Sgibbs		cinfo = &adv->ccb_infos[scsiq.d2.ccb_index];
113055945Sgibbs		ccb = cinfo->ccb;
113139217Sgibbs		ccb->csio.resid = scsiq.remain_bytes;
113255945Sgibbs		adv_done(adv, ccb,
113339217Sgibbs			 scsiq.d3.done_stat, scsiq.d3.host_stat,
113439217Sgibbs			 scsiq.d3.scsi_stat, scsiq.q_no);
113539217Sgibbs
113639217Sgibbs		doneq_head = done_qno;
113740027Sgibbs		done_qno = adv_read_lram_8(adv, done_qaddr + ADV_SCSIQ_B_FWD);
113839217Sgibbs	}
113939217Sgibbs	adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, doneq_head);
114039217Sgibbs}
114139217Sgibbs
114239217Sgibbs
114339217Sgibbsvoid
114439217Sgibbsadv_done(struct adv_softc *adv, union ccb *ccb, u_int done_stat,
114539217Sgibbs	 u_int host_stat, u_int scsi_status, u_int q_no)
114639217Sgibbs{
114739217Sgibbs	struct	   adv_ccb_info *cinfo;
114839217Sgibbs
114939217Sgibbs	cinfo = (struct adv_ccb_info *)ccb->ccb_h.ccb_cinfo_ptr;
115045443Sgibbs	LIST_REMOVE(&ccb->ccb_h, sim_links.le);
115145443Sgibbs	untimeout(adv_timeout, ccb, ccb->ccb_h.timeout_ch);
115239217Sgibbs	if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
115339217Sgibbs		bus_dmasync_op_t op;
115439217Sgibbs
115539217Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
115639217Sgibbs			op = BUS_DMASYNC_POSTREAD;
115739217Sgibbs		else
115839217Sgibbs			op = BUS_DMASYNC_POSTWRITE;
115939217Sgibbs		bus_dmamap_sync(adv->buffer_dmat, cinfo->dmamap, op);
116039217Sgibbs		bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap);
116139217Sgibbs	}
116239217Sgibbs
116339217Sgibbs	switch (done_stat) {
116439217Sgibbs	case QD_NO_ERROR:
116545443Sgibbs		if (host_stat == QHSTA_NO_ERROR) {
116639217Sgibbs			ccb->ccb_h.status = CAM_REQ_CMP;
116739217Sgibbs			break;
116839217Sgibbs		}
116945443Sgibbs		xpt_print_path(ccb->ccb_h.path);
117045443Sgibbs		printf("adv_done - queue done without error, "
117145443Sgibbs		       "but host status non-zero(%x)\n", host_stat);
117245443Sgibbs		/*FALLTHROUGH*/
117339217Sgibbs	case QD_WITH_ERROR:
117439217Sgibbs		switch (host_stat) {
117545443Sgibbs		case QHSTA_M_TARGET_STATUS_BUSY:
117645443Sgibbs		case QHSTA_M_BAD_QUEUE_FULL_OR_BUSY:
117745443Sgibbs			/*
117845443Sgibbs			 * Assume that if we were a tagged transaction
117945443Sgibbs			 * the target reported queue full.  Otherwise,
118045443Sgibbs			 * report busy.  The firmware really should just
118145443Sgibbs			 * pass the original status back up to us even
118245443Sgibbs			 * if it thinks the target was in error for
118345443Sgibbs			 * returning this status as no other transactions
118445443Sgibbs			 * from this initiator are in effect, but this
118545443Sgibbs			 * ignores multi-initiator setups and there is
118645443Sgibbs			 * evidence that the firmware gets its per-device
118745443Sgibbs			 * transaction counts screwed up occassionally.
118845443Sgibbs			 */
118945443Sgibbs			ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
119045443Sgibbs			if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0
119145443Sgibbs			 && host_stat != QHSTA_M_TARGET_STATUS_BUSY)
119245443Sgibbs				scsi_status = SCSI_STATUS_QUEUE_FULL;
119345443Sgibbs			else
119445443Sgibbs				scsi_status = SCSI_STATUS_BUSY;
119545443Sgibbs			adv_abort_ccb(adv, ccb->ccb_h.target_id,
119645443Sgibbs				      ccb->ccb_h.target_lun,
119745443Sgibbs				      /*ccb*/NULL, CAM_REQUEUE_REQ,
119845443Sgibbs				      /*queued_only*/TRUE);
119945443Sgibbs			/*FALLTHROUGH*/
120045443Sgibbs		case QHSTA_M_NO_AUTO_REQ_SENSE:
120139217Sgibbs		case QHSTA_NO_ERROR:
120239217Sgibbs			ccb->csio.scsi_status = scsi_status;
120339217Sgibbs			switch (scsi_status) {
120439217Sgibbs			case SCSI_STATUS_CHECK_COND:
120539217Sgibbs			case SCSI_STATUS_CMD_TERMINATED:
120639217Sgibbs				ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
120739217Sgibbs				/* Structure copy */
120839217Sgibbs				ccb->csio.sense_data =
120939217Sgibbs				    adv->sense_buffers[q_no - 1];
121039217Sgibbs				/* FALLTHROUGH */
121139217Sgibbs			case SCSI_STATUS_BUSY:
121239217Sgibbs			case SCSI_STATUS_RESERV_CONFLICT:
121339217Sgibbs			case SCSI_STATUS_QUEUE_FULL:
121439217Sgibbs			case SCSI_STATUS_COND_MET:
121539217Sgibbs			case SCSI_STATUS_INTERMED:
121639217Sgibbs			case SCSI_STATUS_INTERMED_COND_MET:
121739217Sgibbs				ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
121839217Sgibbs				break;
121939217Sgibbs			case SCSI_STATUS_OK:
122039217Sgibbs				ccb->ccb_h.status |= CAM_REQ_CMP;
122139217Sgibbs				break;
122239217Sgibbs			}
122339217Sgibbs			break;
122439217Sgibbs		case QHSTA_M_SEL_TIMEOUT:
122539217Sgibbs			ccb->ccb_h.status = CAM_SEL_TIMEOUT;
122639217Sgibbs			break;
122745443Sgibbs		case QHSTA_M_DATA_OVER_RUN:
122845443Sgibbs			ccb->ccb_h.status = CAM_DATA_RUN_ERR;
122945443Sgibbs			break;
123045443Sgibbs		case QHSTA_M_UNEXPECTED_BUS_FREE:
123145443Sgibbs			ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
123245443Sgibbs			break;
123345443Sgibbs		case QHSTA_M_BAD_BUS_PHASE_SEQ:
123445443Sgibbs			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
123545443Sgibbs			break;
123645443Sgibbs		case QHSTA_M_BAD_CMPL_STATUS_IN:
123745443Sgibbs			/* No command complete after a status message */
123845443Sgibbs			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
123945443Sgibbs			break;
124045443Sgibbs		case QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT:
124145443Sgibbs		case QHSTA_M_WTM_TIMEOUT:
124245443Sgibbs		case QHSTA_M_HUNG_REQ_SCSI_BUS_RESET:
124345443Sgibbs			/* The SCSI bus hung in a phase */
124445443Sgibbs			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
124555945Sgibbs			adv_reset_bus(adv, /*initiate_reset*/TRUE);
124645443Sgibbs			break;
124745846Sgibbs		case QHSTA_M_AUTO_REQ_SENSE_FAIL:
124845846Sgibbs			ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
124945846Sgibbs			break;
125045443Sgibbs		case QHSTA_D_QDONE_SG_LIST_CORRUPTED:
125145443Sgibbs		case QHSTA_D_ASC_DVC_ERROR_CODE_SET:
125245443Sgibbs		case QHSTA_D_HOST_ABORT_FAILED:
125345443Sgibbs		case QHSTA_D_EXE_SCSI_Q_FAILED:
125445443Sgibbs		case QHSTA_D_ASPI_NO_BUF_POOL:
125545443Sgibbs		case QHSTA_M_BAD_TAG_CODE:
125645443Sgibbs		case QHSTA_D_LRAM_CMP_ERROR:
125745443Sgibbs		case QHSTA_M_MICRO_CODE_ERROR_HALT:
125839217Sgibbs		default:
125945443Sgibbs			panic("%s: Unhandled Host status error %x",
126045443Sgibbs			      adv_name(adv), host_stat);
126145443Sgibbs			/* NOTREACHED */
126239217Sgibbs		}
126339217Sgibbs		break;
126439217Sgibbs
126539217Sgibbs	case QD_ABORTED_BY_HOST:
126639217Sgibbs		/* Don't clobber any, more explicit, error codes we've set */
126739217Sgibbs		if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG)
126839217Sgibbs			ccb->ccb_h.status = CAM_REQ_ABORTED;
126939217Sgibbs		break;
127039217Sgibbs
127139217Sgibbs	default:
127240733Sgibbs		xpt_print_path(ccb->ccb_h.path);
127340733Sgibbs		printf("adv_done - queue done with unknown status %x:%x\n",
127440733Sgibbs		       done_stat, host_stat);
127539217Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
127639217Sgibbs		break;
127739217Sgibbs	}
127855945Sgibbs	adv_clear_state(adv, ccb);
127939217Sgibbs	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP
128039217Sgibbs	 && (ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
128139217Sgibbs		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
128239217Sgibbs		ccb->ccb_h.status |= CAM_DEV_QFRZN;
128339217Sgibbs	}
128439217Sgibbs	adv_free_ccb_info(adv, cinfo);
128555945Sgibbs	/*
128655945Sgibbs	 * Null this out so that we catch driver bugs that cause a
128755945Sgibbs	 * ccb to be completed twice.
128855945Sgibbs	 */
128955945Sgibbs	ccb->ccb_h.ccb_cinfo_ptr = NULL;
129039217Sgibbs	ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
129139217Sgibbs	xpt_done(ccb);
129239217Sgibbs}
129339217Sgibbs
129439217Sgibbs/*
129539217Sgibbs * Function to poll for command completion when
129639217Sgibbs * interrupts are disabled (crash dumps)
129739217Sgibbs */
129839217Sgibbsstatic void
129939217Sgibbsadv_poll(struct cam_sim *sim)
130039217Sgibbs{
130139217Sgibbs	adv_intr(cam_sim_softc(sim));
130239217Sgibbs}
130339217Sgibbs
130439217Sgibbs/*
130539217Sgibbs * Attach all the sub-devices we can find
130639217Sgibbs */
130739217Sgibbsint
130839217Sgibbsadv_attach(adv)
130939217Sgibbs	struct adv_softc *adv;
131039217Sgibbs{
131139217Sgibbs	struct ccb_setasync csa;
131239217Sgibbs	struct cam_devq *devq;
131355945Sgibbs	int max_sg;
131439217Sgibbs
131539217Sgibbs	/*
131655945Sgibbs	 * Allocate an array of ccb mapping structures.  We put the
131755945Sgibbs	 * index of the ccb_info structure into the queue representing
131855945Sgibbs	 * a transaction and use it for mapping the queue to the
131955945Sgibbs	 * upper level SCSI transaction it represents.
132055945Sgibbs	 */
132155945Sgibbs	adv->ccb_infos = malloc(sizeof(*adv->ccb_infos) * adv->max_openings,
132255945Sgibbs				M_DEVBUF, M_NOWAIT);
132355945Sgibbs
132455945Sgibbs	if (adv->ccb_infos == NULL)
132555945Sgibbs		goto error_exit;
132655945Sgibbs
132755945Sgibbs	adv->init_level++;
132855945Sgibbs
132955945Sgibbs	/*
133039217Sgibbs	 * Create our DMA tags.  These tags define the kinds of device
133139217Sgibbs	 * accessable memory allocations and memory mappings we will
133239217Sgibbs	 * need to perform during normal operation.
133339217Sgibbs	 *
133439217Sgibbs	 * Unless we need to further restrict the allocation, we rely
133539217Sgibbs	 * on the restrictions of the parent dmat, hence the common
133639217Sgibbs	 * use of MAXADDR and MAXSIZE.
133755945Sgibbs	 *
133855945Sgibbs	 * The ASC boards use chains of "queues" (the transactional
133955945Sgibbs	 * resources on the board) to represent long S/G lists.
134055945Sgibbs	 * The first queue represents the command and holds a
134155945Sgibbs	 * single address and data pair.  The queues that follow
134255945Sgibbs	 * can each hold ADV_SG_LIST_PER_Q entries.  Given the
134355945Sgibbs	 * total number of queues, we can express the largest
134455945Sgibbs	 * transaction we can map.  We reserve a few queues for
134555945Sgibbs	 * error recovery.  Take those into account as well.
134655945Sgibbs	 *
134755945Sgibbs	 * There is a way to take an interrupt to download the
134855945Sgibbs	 * next batch of S/G entries if there are more than 255
134955945Sgibbs	 * of them (the counter in the queue structure is a u_int8_t).
135055945Sgibbs	 * We don't use this feature, so limit the S/G list size
135155945Sgibbs	 * accordingly.
135239217Sgibbs	 */
135355945Sgibbs	max_sg = (adv->max_openings - ADV_MIN_FREE_Q - 1) * ADV_SG_LIST_PER_Q;
135455945Sgibbs	if (max_sg > 255)
135555945Sgibbs		max_sg = 255;
135639217Sgibbs
135739217Sgibbs	/* DMA tag for mapping buffers into device visible space. */
135849860Sgibbs	if (bus_dma_tag_create(adv->parent_dmat, /*alignment*/1, /*boundary*/0,
135939217Sgibbs			       /*lowaddr*/BUS_SPACE_MAXADDR,
136039217Sgibbs			       /*highaddr*/BUS_SPACE_MAXADDR,
136139217Sgibbs			       /*filter*/NULL, /*filterarg*/NULL,
136255945Sgibbs			       /*maxsize*/MAXPHYS,
136355945Sgibbs			       /*nsegments*/max_sg,
136439217Sgibbs			       /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
136539217Sgibbs			       /*flags*/BUS_DMA_ALLOCNOW,
136639217Sgibbs			       &adv->buffer_dmat) != 0) {
136739217Sgibbs		goto error_exit;
136839217Sgibbs	}
136939217Sgibbs	adv->init_level++;
137039217Sgibbs
137139217Sgibbs	/* DMA tag for our sense buffers */
137249860Sgibbs	if (bus_dma_tag_create(adv->parent_dmat, /*alignment*/1, /*boundary*/0,
137339217Sgibbs			       /*lowaddr*/BUS_SPACE_MAXADDR,
137439217Sgibbs			       /*highaddr*/BUS_SPACE_MAXADDR,
137539217Sgibbs			       /*filter*/NULL, /*filterarg*/NULL,
137639217Sgibbs			       sizeof(struct scsi_sense_data)*adv->max_openings,
137739217Sgibbs			       /*nsegments*/1,
137839217Sgibbs			       /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
137939217Sgibbs			       /*flags*/0, &adv->sense_dmat) != 0) {
138039217Sgibbs		goto error_exit;
138139217Sgibbs        }
138239217Sgibbs
138339217Sgibbs	adv->init_level++;
138439217Sgibbs
138539217Sgibbs	/* Allocation for our sense buffers */
138639217Sgibbs	if (bus_dmamem_alloc(adv->sense_dmat, (void **)&adv->sense_buffers,
138739217Sgibbs			     BUS_DMA_NOWAIT, &adv->sense_dmamap) != 0) {
138839217Sgibbs		goto error_exit;
138939217Sgibbs	}
139039217Sgibbs
139139217Sgibbs	adv->init_level++;
139239217Sgibbs
139339217Sgibbs	/* And permanently map them */
139439217Sgibbs	bus_dmamap_load(adv->sense_dmat, adv->sense_dmamap,
139539217Sgibbs       			adv->sense_buffers,
139639217Sgibbs			sizeof(struct scsi_sense_data)*adv->max_openings,
139739217Sgibbs			adv_map, &adv->sense_physbase, /*flags*/0);
139839217Sgibbs
139939217Sgibbs	adv->init_level++;
140039217Sgibbs
140139217Sgibbs	/*
140239217Sgibbs	 * Fire up the chip
140339217Sgibbs	 */
140439217Sgibbs	if (adv_start_chip(adv) != 1) {
140539217Sgibbs		printf("adv%d: Unable to start on board processor. Aborting.\n",
140639217Sgibbs		       adv->unit);
140739217Sgibbs		return (0);
140839217Sgibbs	}
140939217Sgibbs
141039217Sgibbs	/*
141139217Sgibbs	 * Create the device queue for our SIM.
141239217Sgibbs	 */
141339217Sgibbs	devq = cam_simq_alloc(adv->max_openings);
141439217Sgibbs	if (devq == NULL)
141539217Sgibbs		return (0);
141639217Sgibbs
141739217Sgibbs	/*
141839217Sgibbs	 * Construct our SIM entry.
141939217Sgibbs	 */
142039217Sgibbs	adv->sim = cam_sim_alloc(adv_action, adv_poll, "adv", adv, adv->unit,
142139217Sgibbs				 1, adv->max_openings, devq);
142239217Sgibbs	if (adv->sim == NULL)
142339217Sgibbs		return (0);
142439217Sgibbs
142539217Sgibbs	/*
142639217Sgibbs	 * Register the bus.
142739217Sgibbs	 *
142839217Sgibbs	 * XXX Twin Channel EISA Cards???
142939217Sgibbs	 */
143039217Sgibbs	if (xpt_bus_register(adv->sim, 0) != CAM_SUCCESS) {
143139217Sgibbs		cam_sim_free(adv->sim, /*free devq*/TRUE);
143239217Sgibbs		return (0);
143339217Sgibbs	}
143439217Sgibbs
143539217Sgibbs	if (xpt_create_path(&adv->path, /*periph*/NULL, cam_sim_path(adv->sim),
143639217Sgibbs			    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD)
143739217Sgibbs	   == CAM_REQ_CMP) {
143839217Sgibbs		xpt_setup_ccb(&csa.ccb_h, adv->path, /*priority*/5);
143939217Sgibbs		csa.ccb_h.func_code = XPT_SASYNC_CB;
144039217Sgibbs		csa.event_enable = AC_FOUND_DEVICE|AC_LOST_DEVICE;
144139217Sgibbs		csa.callback = advasync;
144239217Sgibbs		csa.callback_arg = adv;
144339217Sgibbs		xpt_action((union ccb *)&csa);
144439217Sgibbs	}
144539217Sgibbs	return (1);
144639217Sgibbs
144739217Sgibbserror_exit:
144839217Sgibbs	return (0);
144939217Sgibbs}
1450