advlib.c revision 139749
1139749Simp/*-
218781Sgibbs * Low level routines for the Advanced Systems Inc. SCSI controllers chips
318781Sgibbs *
455945Sgibbs * Copyright (c) 1996-1997, 1999-2000 Justin Gibbs.
518781Sgibbs * All rights reserved.
618781Sgibbs *
718781Sgibbs * Redistribution and use in source and binary forms, with or without
818781Sgibbs * modification, are permitted provided that the following conditions
918781Sgibbs * are met:
1018781Sgibbs * 1. Redistributions of source code must retain the above copyright
1139217Sgibbs *    notice, this list of conditions, and the following disclaimer,
1239217Sgibbs *    without modification, immediately at the beginning of the file.
1318781Sgibbs * 2. Redistributions in binary form must reproduce the above copyright
1418781Sgibbs *    notice, this list of conditions and the following disclaimer in the
1518781Sgibbs *    documentation and/or other materials provided with the distribution.
1618781Sgibbs * 3. The name of the author may not be used to endorse or promote products
1718781Sgibbs *    derived from this software without specific prior written permission.
1818781Sgibbs *
1918781Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2018781Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2118781Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2218781Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2318781Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2418781Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2518781Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2618781Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2718781Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2818781Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2918781Sgibbs * SUCH DAMAGE.
3018781Sgibbs */
31139749Simp/*-
3218781Sgibbs * Ported from:
3318781Sgibbs * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
3418781Sgibbs *
3518781Sgibbs * Copyright (c) 1995-1996 Advanced System Products, Inc.
3618781Sgibbs * All Rights Reserved.
3718781Sgibbs *
3818781Sgibbs * Redistribution and use in source and binary forms, with or without
3918781Sgibbs * modification, are permitted provided that redistributions of source
4018781Sgibbs * code retain the above copyright notice and this comment without
4118781Sgibbs * modification.
4218781Sgibbs */
4318781Sgibbs
44119418Sobrien#include <sys/cdefs.h>
45119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/advansys/advlib.c 139749 2005-01-06 01:43:34Z imp $");
46119418Sobrien
4718781Sgibbs#include <sys/param.h>
4845846Sgibbs#include <sys/kernel.h>
4918781Sgibbs#include <sys/systm.h>
5018781Sgibbs
5139217Sgibbs#include <machine/bus_pio.h>
5239217Sgibbs#include <machine/bus.h>
5359082Snyan#include <machine/resource.h>
5459082Snyan#include <sys/bus.h>
5559082Snyan#include <sys/rman.h>
5618781Sgibbs
5739217Sgibbs#include <cam/cam.h>
5839217Sgibbs#include <cam/cam_ccb.h>
5939217Sgibbs#include <cam/cam_sim.h>
6039217Sgibbs#include <cam/cam_xpt_sim.h>
6118781Sgibbs
6239217Sgibbs#include <cam/scsi/scsi_all.h>
6339217Sgibbs#include <cam/scsi/scsi_message.h>
6439217Sgibbs#include <cam/scsi/scsi_da.h>
6539217Sgibbs#include <cam/scsi/scsi_cd.h>
6639217Sgibbs
6718781Sgibbs#include <vm/vm.h>
6818781Sgibbs#include <vm/vm_param.h>
6918781Sgibbs#include <vm/pmap.h>
7018781Sgibbs
7139217Sgibbs#include <dev/advansys/advansys.h>
7218781Sgibbs#include <dev/advansys/advmcode.h>
7318781Sgibbs
7439217Sgibbsstruct adv_quirk_entry {
7539217Sgibbs	struct scsi_inquiry_pattern inq_pat;
7639217Sgibbs	u_int8_t quirks;
7739217Sgibbs#define ADV_QUIRK_FIX_ASYN_XFER_ALWAYS	0x01
7839217Sgibbs#define ADV_QUIRK_FIX_ASYN_XFER		0x02
7939217Sgibbs};
8039217Sgibbs
8139217Sgibbsstatic struct adv_quirk_entry adv_quirk_table[] =
8239217Sgibbs{
8339217Sgibbs	{
8439217Sgibbs		{ T_CDROM, SIP_MEDIA_REMOVABLE, "HP", "*", "*" },
8539217Sgibbs		ADV_QUIRK_FIX_ASYN_XFER_ALWAYS|ADV_QUIRK_FIX_ASYN_XFER
8639217Sgibbs	},
8739217Sgibbs	{
8839217Sgibbs		{ T_CDROM, SIP_MEDIA_REMOVABLE, "NEC", "CD-ROM DRIVE", "*" },
8939217Sgibbs		0
9039217Sgibbs	},
9139217Sgibbs	{
9239217Sgibbs		{
9339217Sgibbs		  T_SEQUENTIAL, SIP_MEDIA_REMOVABLE,
9439217Sgibbs		  "TANDBERG", " TDC 36", "*"
9539217Sgibbs		},
9639217Sgibbs		0
9739217Sgibbs	},
9839217Sgibbs	{
9939217Sgibbs		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "WANGTEK", "*", "*" },
10039217Sgibbs		0
10139217Sgibbs	},
10239217Sgibbs	{
10339217Sgibbs		{
10439217Sgibbs		  T_PROCESSOR, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
10539217Sgibbs		  "*", "*", "*"
10639217Sgibbs		},
10739217Sgibbs		0
10839217Sgibbs	},
10939217Sgibbs	{
11039217Sgibbs		{
11139217Sgibbs		  T_SCANNER, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
11239217Sgibbs		  "*", "*", "*"
11339217Sgibbs		},
11439217Sgibbs		0
11539217Sgibbs	},
11639217Sgibbs	{
11739217Sgibbs		/* Default quirk entry */
11839217Sgibbs		{
11939217Sgibbs		  T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
12039217Sgibbs		  /*vendor*/"*", /*product*/"*", /*revision*/"*"
12139217Sgibbs                },
12239217Sgibbs                ADV_QUIRK_FIX_ASYN_XFER,
12339217Sgibbs	}
12439217Sgibbs};
12539217Sgibbs
12618781Sgibbs/*
12718781Sgibbs * Allowable periods in ns
12818781Sgibbs */
12945575Seivindstatic u_int8_t adv_sdtr_period_tbl[] =
13018781Sgibbs{
13118781Sgibbs	25,
13218781Sgibbs	30,
13318781Sgibbs	35,
13418781Sgibbs	40,
13518781Sgibbs	50,
13618781Sgibbs	60,
13718781Sgibbs	70,
13818781Sgibbs	85
13918781Sgibbs};
14018781Sgibbs
14145575Seivindstatic u_int8_t adv_sdtr_period_tbl_ultra[] =
14239217Sgibbs{
14339217Sgibbs	12,
14439217Sgibbs	19,
14539217Sgibbs	25,
14639217Sgibbs	32,
14739217Sgibbs	38,
14839217Sgibbs	44,
14939217Sgibbs	50,
15039217Sgibbs	57,
15139217Sgibbs	63,
15239217Sgibbs	69,
15339217Sgibbs	75,
15439217Sgibbs	82,
15539217Sgibbs	88,
15639217Sgibbs	94,
15739217Sgibbs	100,
15839217Sgibbs	107
15918781Sgibbs};
16018781Sgibbs
16139217Sgibbsstruct ext_msg {
16239217Sgibbs	u_int8_t msg_type;
16339217Sgibbs	u_int8_t msg_len;
16439217Sgibbs	u_int8_t msg_req;
16539217Sgibbs	union {
16639217Sgibbs		struct {
16739217Sgibbs			u_int8_t sdtr_xfer_period;
16839217Sgibbs			u_int8_t sdtr_req_ack_offset;
16939217Sgibbs		} sdtr;
17039217Sgibbs		struct {
17139217Sgibbs       			u_int8_t wdtr_width;
17239217Sgibbs		} wdtr;
17339217Sgibbs		struct {
17439217Sgibbs			u_int8_t mdp[4];
17539217Sgibbs		} mdp;
17639217Sgibbs	} u_ext_msg;
17739217Sgibbs	u_int8_t res;
17839217Sgibbs};
17939217Sgibbs
18039217Sgibbs#define	xfer_period	u_ext_msg.sdtr.sdtr_xfer_period
18139217Sgibbs#define	req_ack_offset	u_ext_msg.sdtr.sdtr_req_ack_offset
18239217Sgibbs#define	wdtr_width	u_ext_msg.wdtr.wdtr_width
18339217Sgibbs#define	mdp_b3		u_ext_msg.mdp_b3
18439217Sgibbs#define	mdp_b2		u_ext_msg.mdp_b2
18539217Sgibbs#define	mdp_b1		u_ext_msg.mdp_b1
18639217Sgibbs#define	mdp_b0		u_ext_msg.mdp_b0
18739217Sgibbs
18818781Sgibbs/*
18918781Sgibbs * Some of the early PCI adapters have problems with
19039217Sgibbs * async transfers.  Instead use an offset of 1.
19118781Sgibbs */
19239217Sgibbs#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
19318781Sgibbs
19418781Sgibbs/* LRAM routines */
19539217Sgibbsstatic void	 adv_read_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr,
19639217Sgibbs					u_int16_t *buffer, int count);
19739217Sgibbsstatic void	 adv_write_lram_16_multi(struct adv_softc *adv,
19839217Sgibbs					 u_int16_t s_addr, u_int16_t *buffer,
19939217Sgibbs					 int count);
20039217Sgibbsstatic void	 adv_mset_lram_16(struct adv_softc *adv, u_int16_t s_addr,
20139217Sgibbs				  u_int16_t set_value, int count);
20239217Sgibbsstatic u_int32_t adv_msum_lram_16(struct adv_softc *adv, u_int16_t s_addr,
20339217Sgibbs				  int count);
20418781Sgibbs
20539217Sgibbsstatic int	 adv_write_and_verify_lram_16(struct adv_softc *adv,
20639217Sgibbs					      u_int16_t addr, u_int16_t value);
20739217Sgibbsstatic u_int32_t adv_read_lram_32(struct adv_softc *adv, u_int16_t addr);
20818781Sgibbs
20918781Sgibbs
21039217Sgibbsstatic void	 adv_write_lram_32(struct adv_softc *adv, u_int16_t addr,
21139217Sgibbs				   u_int32_t value);
21239217Sgibbsstatic void	 adv_write_lram_32_multi(struct adv_softc *adv,
21339217Sgibbs					 u_int16_t s_addr, u_int32_t *buffer,
21439217Sgibbs					 int count);
21518781Sgibbs
21618781Sgibbs/* EEPROM routines */
21739217Sgibbsstatic u_int16_t adv_read_eeprom_16(struct adv_softc *adv, u_int8_t addr);
21839217Sgibbsstatic u_int16_t adv_write_eeprom_16(struct adv_softc *adv, u_int8_t addr,
21939217Sgibbs				     u_int16_t value);
22039217Sgibbsstatic int	 adv_write_eeprom_cmd_reg(struct adv_softc *adv,
22139217Sgibbs					  u_int8_t cmd_reg);
22239217Sgibbsstatic int	 adv_set_eeprom_config_once(struct adv_softc *adv,
22339217Sgibbs					    struct adv_eeprom_config *eeconfig);
22418781Sgibbs
22518781Sgibbs/* Initialization */
22639217Sgibbsstatic u_int32_t adv_load_microcode(struct adv_softc *adv, u_int16_t s_addr,
22739217Sgibbs				    u_int16_t *mcode_buf, u_int16_t mcode_size);
22818781Sgibbs
22939217Sgibbsstatic void	 adv_reinit_lram(struct adv_softc *adv);
23039217Sgibbsstatic void	 adv_init_lram(struct adv_softc *adv);
23139217Sgibbsstatic int	 adv_init_microcode_var(struct adv_softc *adv);
23239217Sgibbsstatic void	 adv_init_qlink_var(struct adv_softc *adv);
23339217Sgibbs
23418781Sgibbs/* Interrupts */
23539217Sgibbsstatic void	 adv_disable_interrupt(struct adv_softc *adv);
23639217Sgibbsstatic void	 adv_enable_interrupt(struct adv_softc *adv);
23739217Sgibbsstatic void	 adv_toggle_irq_act(struct adv_softc *adv);
23818781Sgibbs
23918781Sgibbs/* Chip Control */
24039217Sgibbsstatic int	 adv_host_req_chip_halt(struct adv_softc *adv);
24139217Sgibbsstatic void	 adv_set_chip_ih(struct adv_softc *adv, u_int16_t ins_code);
24218781Sgibbs#if UNUSED
24339217Sgibbsstatic u_int8_t  adv_get_chip_scsi_ctrl(struct adv_softc *adv);
24418781Sgibbs#endif
24518781Sgibbs
24618781Sgibbs/* Queue handling and execution */
24740027Sgibbsstatic __inline int
24840027Sgibbs		 adv_sgcount_to_qcount(int sgcount);
24940027Sgibbs
25040027Sgibbsstatic __inline int
25140027Sgibbsadv_sgcount_to_qcount(int sgcount)
25240027Sgibbs{
25340027Sgibbs	int	n_sg_list_qs;
25440027Sgibbs
25540027Sgibbs	n_sg_list_qs = ((sgcount - 1) / ADV_SG_LIST_PER_Q);
25640027Sgibbs	if (((sgcount - 1) % ADV_SG_LIST_PER_Q) != 0)
25740027Sgibbs		n_sg_list_qs++;
25840027Sgibbs	return (n_sg_list_qs + 1);
25940027Sgibbs}
26040027Sgibbs
261111409Sobrien#if BYTE_ORDER == BIG_ENDIAN
262111342Sobrienstatic void	 adv_adj_endian_qdone_info(struct adv_q_done_info *);
263111342Sobrienstatic void	 adv_adj_scsiq_endian(struct adv_scsi_q *);
264111409Sobrien#endif
26539217Sgibbsstatic void	 adv_get_q_info(struct adv_softc *adv, u_int16_t s_addr,
26639217Sgibbs				u_int16_t *inbuf, int words);
26739217Sgibbsstatic u_int	 adv_get_num_free_queues(struct adv_softc *adv, u_int8_t n_qs);
26839217Sgibbsstatic u_int8_t  adv_alloc_free_queues(struct adv_softc *adv,
26939217Sgibbs				       u_int8_t free_q_head, u_int8_t n_free_q);
27039217Sgibbsstatic u_int8_t  adv_alloc_free_queue(struct adv_softc *adv,
27139217Sgibbs				      u_int8_t free_q_head);
27239217Sgibbsstatic int	 adv_send_scsi_queue(struct adv_softc *adv,
27339217Sgibbs				     struct adv_scsi_q *scsiq,
27439217Sgibbs				     u_int8_t n_q_required);
27539217Sgibbsstatic void	 adv_put_ready_sg_list_queue(struct adv_softc *adv,
27639217Sgibbs					     struct adv_scsi_q *scsiq,
27739217Sgibbs					     u_int q_no);
27839217Sgibbsstatic void	 adv_put_ready_queue(struct adv_softc *adv,
27939217Sgibbs				     struct adv_scsi_q *scsiq, u_int q_no);
28039217Sgibbsstatic void	 adv_put_scsiq(struct adv_softc *adv, u_int16_t s_addr,
28139217Sgibbs			       u_int16_t *buffer, int words);
28218781Sgibbs
28339217Sgibbs/* Messages */
28439217Sgibbsstatic void	 adv_handle_extmsg_in(struct adv_softc *adv,
28539217Sgibbs				      u_int16_t halt_q_addr, u_int8_t q_cntl,
28639217Sgibbs				      target_bit_vector target_id,
28739217Sgibbs				      int tid);
28839217Sgibbsstatic void	 adv_msgout_sdtr(struct adv_softc *adv, u_int8_t sdtr_period,
28939217Sgibbs				 u_int8_t sdtr_offset);
29039217Sgibbsstatic void	 adv_set_sdtr_reg_at_id(struct adv_softc *adv, int id,
29139217Sgibbs					u_int8_t sdtr_data);
29218781Sgibbs
29318781Sgibbs
29419426Sgibbs/* Exported functions first */
29518781Sgibbs
29639217Sgibbsvoid
29739217Sgibbsadvasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
29839217Sgibbs{
29918781Sgibbs	struct adv_softc *adv;
30039217Sgibbs
30139217Sgibbs	adv = (struct adv_softc *)callback_arg;
30239217Sgibbs	switch (code) {
30339217Sgibbs	case AC_FOUND_DEVICE:
30439217Sgibbs	{
30539217Sgibbs		struct ccb_getdev *cgd;
30639217Sgibbs		target_bit_vector target_mask;
30739217Sgibbs		int num_entries;
30839217Sgibbs        	caddr_t match;
30939217Sgibbs		struct adv_quirk_entry *entry;
31039217Sgibbs		struct adv_target_transinfo* tinfo;
31139217Sgibbs
31239217Sgibbs		cgd = (struct ccb_getdev *)arg;
31339217Sgibbs
31439217Sgibbs		target_mask = ADV_TID_TO_TARGET_MASK(cgd->ccb_h.target_id);
31539217Sgibbs
31639217Sgibbs		num_entries = sizeof(adv_quirk_table)/sizeof(*adv_quirk_table);
31739217Sgibbs		match = cam_quirkmatch((caddr_t)&cgd->inq_data,
31839217Sgibbs				       (caddr_t)adv_quirk_table,
31939217Sgibbs				       num_entries, sizeof(*adv_quirk_table),
32039217Sgibbs				       scsi_inquiry_match);
32139217Sgibbs
32239217Sgibbs		if (match == NULL)
32339217Sgibbs			panic("advasync: device didn't match wildcard entry!!");
32439217Sgibbs
32539217Sgibbs		entry = (struct adv_quirk_entry *)match;
32639217Sgibbs
32739217Sgibbs		if (adv->bug_fix_control & ADV_BUG_FIX_ASYN_USE_SYN) {
32839217Sgibbs			if ((entry->quirks & ADV_QUIRK_FIX_ASYN_XFER_ALWAYS)!=0)
32939217Sgibbs				adv->fix_asyn_xfer_always |= target_mask;
33039217Sgibbs			else
33139217Sgibbs				adv->fix_asyn_xfer_always &= ~target_mask;
33239217Sgibbs			/*
33339217Sgibbs			 * We start out life with all bits set and clear them
33439217Sgibbs			 * after we've determined that the fix isn't necessary.
33539217Sgibbs			 * It may well be that we've already cleared a target
33639217Sgibbs			 * before the full inquiry session completes, so don't
33739217Sgibbs			 * gratuitously set a target bit even if it has this
33839217Sgibbs			 * quirk.  But, if the quirk exonerates a device, clear
33939217Sgibbs			 * the bit now.
34039217Sgibbs			 */
34139217Sgibbs			if ((entry->quirks & ADV_QUIRK_FIX_ASYN_XFER) == 0)
34239217Sgibbs				adv->fix_asyn_xfer &= ~target_mask;
34339217Sgibbs		}
34439217Sgibbs		/*
34539217Sgibbs		 * Reset our sync settings now that we've determined
34639217Sgibbs		 * what quirks are in effect for the device.
34739217Sgibbs		 */
34839217Sgibbs		tinfo = &adv->tinfo[cgd->ccb_h.target_id];
34939217Sgibbs		adv_set_syncrate(adv, cgd->ccb_h.path,
35039217Sgibbs				 cgd->ccb_h.target_id,
35139217Sgibbs				 tinfo->current.period,
35239217Sgibbs				 tinfo->current.offset,
35339217Sgibbs				 ADV_TRANS_CUR);
35439217Sgibbs		break;
35539217Sgibbs	}
35639217Sgibbs	case AC_LOST_DEVICE:
35739217Sgibbs	{
35839217Sgibbs		u_int target_mask;
35939217Sgibbs
36039217Sgibbs		if (adv->bug_fix_control & ADV_BUG_FIX_ASYN_USE_SYN) {
36139217Sgibbs			target_mask = 0x01 << xpt_path_target_id(path);
36239217Sgibbs			adv->fix_asyn_xfer |= target_mask;
36339217Sgibbs		}
36439217Sgibbs
36539217Sgibbs		/*
36639217Sgibbs		 * Revert to async transfers
36739217Sgibbs		 * for the next device.
36839217Sgibbs		 */
36939217Sgibbs		adv_set_syncrate(adv, /*path*/NULL,
37039217Sgibbs				 xpt_path_target_id(path),
37139217Sgibbs				 /*period*/0,
37239217Sgibbs				 /*offset*/0,
37339217Sgibbs				 ADV_TRANS_GOAL|ADV_TRANS_CUR);
37439217Sgibbs	}
37539217Sgibbs	default:
37639217Sgibbs		break;
37739217Sgibbs	}
37839217Sgibbs}
37939217Sgibbs
38039217Sgibbsvoid
38139217Sgibbsadv_set_bank(struct adv_softc *adv, u_int8_t bank)
38218781Sgibbs{
38339217Sgibbs	u_int8_t control;
38439217Sgibbs
38539217Sgibbs	/*
38639217Sgibbs	 * Start out with the bank reset to 0
38739217Sgibbs	 */
38839217Sgibbs	control = ADV_INB(adv, ADV_CHIP_CTRL)
38939217Sgibbs		  &  (~(ADV_CC_SINGLE_STEP | ADV_CC_TEST
39039217Sgibbs			| ADV_CC_DIAG | ADV_CC_SCSI_RESET
39139217Sgibbs			| ADV_CC_CHIP_RESET | ADV_CC_BANK_ONE));
39239217Sgibbs	if (bank == 1) {
39339217Sgibbs		control |= ADV_CC_BANK_ONE;
39439217Sgibbs	} else if (bank == 2) {
39539217Sgibbs		control |= ADV_CC_DIAG | ADV_CC_BANK_ONE;
39639217Sgibbs	}
39739217Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, control);
39839217Sgibbs}
39939217Sgibbs
40039217Sgibbsu_int8_t
40139217Sgibbsadv_read_lram_8(struct adv_softc *adv, u_int16_t addr)
40239217Sgibbs{
40318781Sgibbs	u_int8_t   byte_data;
40418781Sgibbs	u_int16_t  word_data;
40518781Sgibbs
40618781Sgibbs	/*
40718781Sgibbs	 * LRAM is accessed on 16bit boundaries.
40818781Sgibbs	 */
40918781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr & 0xFFFE);
41018781Sgibbs	word_data = ADV_INW(adv, ADV_LRAM_DATA);
41118781Sgibbs	if (addr & 1) {
41218781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
41318781Sgibbs		byte_data = (u_int8_t)(word_data & 0xFF);
41418781Sgibbs#else
41518781Sgibbs		byte_data = (u_int8_t)((word_data >> 8) & 0xFF);
41618781Sgibbs#endif
41718781Sgibbs	} else {
41818781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
41918781Sgibbs		byte_data = (u_int8_t)((word_data >> 8) & 0xFF);
42018781Sgibbs#else
42118781Sgibbs		byte_data = (u_int8_t)(word_data & 0xFF);
42218781Sgibbs#endif
42318781Sgibbs	}
42418781Sgibbs	return (byte_data);
42518781Sgibbs}
42618781Sgibbs
42718781Sgibbsvoid
42839217Sgibbsadv_write_lram_8(struct adv_softc *adv, u_int16_t addr, u_int8_t value)
42918781Sgibbs{
43018781Sgibbs	u_int16_t word_data;
43118781Sgibbs
43218781Sgibbs	word_data = adv_read_lram_16(adv, addr & 0xFFFE);
43318781Sgibbs	if (addr & 1) {
43418781Sgibbs		word_data &= 0x00FF;
43518781Sgibbs		word_data |= (((u_int8_t)value << 8) & 0xFF00);
43618781Sgibbs	} else {
43718781Sgibbs		word_data &= 0xFF00;
43818781Sgibbs		word_data |= ((u_int8_t)value & 0x00FF);
43918781Sgibbs	}
44018781Sgibbs	adv_write_lram_16(adv, addr & 0xFFFE, word_data);
44118781Sgibbs}
44218781Sgibbs
44318781Sgibbs
44418781Sgibbsu_int16_t
44539217Sgibbsadv_read_lram_16(struct adv_softc *adv, u_int16_t addr)
44618781Sgibbs{
44718781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
44818781Sgibbs	return (ADV_INW(adv, ADV_LRAM_DATA));
44918781Sgibbs}
45018781Sgibbs
45118781Sgibbsvoid
45239217Sgibbsadv_write_lram_16(struct adv_softc *adv, u_int16_t addr, u_int16_t value)
45318781Sgibbs{
45418781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
45518781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, value);
45618781Sgibbs}
45718781Sgibbs
45818781Sgibbs/*
45939217Sgibbs * Determine if there is a board at "iobase" by looking
46039217Sgibbs * for the AdvanSys signatures.  Return 1 if a board is
46139217Sgibbs * found, 0 otherwise.
46218781Sgibbs */
46339217Sgibbsint
46439217Sgibbsadv_find_signature(bus_space_tag_t tag, bus_space_handle_t bsh)
46539217Sgibbs{
46639217Sgibbs	u_int16_t signature;
46739217Sgibbs
46839217Sgibbs	if (bus_space_read_1(tag, bsh, ADV_SIGNATURE_BYTE) == ADV_1000_ID1B) {
46939217Sgibbs		signature = bus_space_read_2(tag, bsh, ADV_SIGNATURE_WORD);
47039217Sgibbs		if ((signature == ADV_1000_ID0W)
47139217Sgibbs		 || (signature == ADV_1000_ID0W_FIX))
47239217Sgibbs			return (1);
47339217Sgibbs	}
47439217Sgibbs	return (0);
47539217Sgibbs}
47639217Sgibbs
47718781Sgibbsvoid
47839217Sgibbsadv_lib_init(struct adv_softc *adv)
47918781Sgibbs{
48039217Sgibbs	if ((adv->type & ADV_ULTRA) != 0) {
48139217Sgibbs		adv->sdtr_period_tbl = adv_sdtr_period_tbl_ultra;
48239217Sgibbs		adv->sdtr_period_tbl_size = sizeof(adv_sdtr_period_tbl_ultra);
48339217Sgibbs	} else {
48439217Sgibbs		adv->sdtr_period_tbl = adv_sdtr_period_tbl;
48539217Sgibbs		adv->sdtr_period_tbl_size = sizeof(adv_sdtr_period_tbl);
48639217Sgibbs	}
48718781Sgibbs}
48818781Sgibbs
48918781Sgibbsu_int16_t
49039217Sgibbsadv_get_eeprom_config(struct adv_softc *adv, struct
49139217Sgibbs		      adv_eeprom_config  *eeprom_config)
49218781Sgibbs{
49318781Sgibbs	u_int16_t	sum;
49418781Sgibbs	u_int16_t	*wbuf;
49518781Sgibbs	u_int8_t	cfg_beg;
49618781Sgibbs	u_int8_t	cfg_end;
49718781Sgibbs	u_int8_t	s_addr;
49818781Sgibbs
49918781Sgibbs	wbuf = (u_int16_t *)eeprom_config;
50018781Sgibbs	sum = 0;
50118781Sgibbs
50218781Sgibbs	for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
50318781Sgibbs		*wbuf = adv_read_eeprom_16(adv, s_addr);
50418781Sgibbs		sum += *wbuf;
50518781Sgibbs	}
50618781Sgibbs
50718781Sgibbs	if (adv->type & ADV_VL) {
50818781Sgibbs		cfg_beg = ADV_EEPROM_CFG_BEG_VL;
50918781Sgibbs		cfg_end = ADV_EEPROM_MAX_ADDR_VL;
51018781Sgibbs	} else {
51118781Sgibbs		cfg_beg = ADV_EEPROM_CFG_BEG;
51218781Sgibbs		cfg_end = ADV_EEPROM_MAX_ADDR;
51318781Sgibbs	}
51418781Sgibbs
51518781Sgibbs	for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
51618781Sgibbs		*wbuf = adv_read_eeprom_16(adv, s_addr);
51718781Sgibbs		sum += *wbuf;
51818781Sgibbs#if ADV_DEBUG_EEPROM
51918781Sgibbs		printf("Addr 0x%x: 0x%04x\n", s_addr, *wbuf);
52018781Sgibbs#endif
52118781Sgibbs	}
52218781Sgibbs	*wbuf = adv_read_eeprom_16(adv, s_addr);
52318781Sgibbs	return (sum);
52418781Sgibbs}
52518781Sgibbs
52618781Sgibbsint
52739217Sgibbsadv_set_eeprom_config(struct adv_softc *adv,
52839217Sgibbs		      struct adv_eeprom_config *eeprom_config)
52918781Sgibbs{
53018781Sgibbs	int	retry;
53118781Sgibbs
53218781Sgibbs	retry = 0;
53318781Sgibbs	while (1) {
53418781Sgibbs		if (adv_set_eeprom_config_once(adv, eeprom_config) == 0) {
53518781Sgibbs			break;
53618781Sgibbs		}
53718781Sgibbs		if (++retry > ADV_EEPROM_MAX_RETRY) {
53818781Sgibbs			break;
53918781Sgibbs		}
54018781Sgibbs	}
54118781Sgibbs	return (retry > ADV_EEPROM_MAX_RETRY);
54218781Sgibbs}
54318781Sgibbs
54418781Sgibbsint
54555945Sgibbsadv_reset_chip(struct adv_softc *adv, int reset_bus)
54618781Sgibbs{
54718781Sgibbs	adv_stop_chip(adv);
54855945Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_CHIP_RESET | ADV_CC_HALT
54955945Sgibbs				     | (reset_bus ? ADV_CC_SCSI_RESET : 0));
55055945Sgibbs	DELAY(60);
55118781Sgibbs
55218781Sgibbs	adv_set_chip_ih(adv, ADV_INS_RFLAG_WTM);
55318781Sgibbs	adv_set_chip_ih(adv, ADV_INS_HALT);
55418781Sgibbs
55555945Sgibbs	if (reset_bus)
55655945Sgibbs		ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_CHIP_RESET | ADV_CC_HALT);
55755945Sgibbs
55818781Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT);
55955945Sgibbs	if (reset_bus)
56055945Sgibbs		DELAY(200 * 1000);
56155945Sgibbs
56255945Sgibbs	ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_CLR_SCSI_RESET_INT);
56355945Sgibbs	ADV_OUTW(adv, ADV_CHIP_STATUS, 0);
56418781Sgibbs	return (adv_is_chip_halted(adv));
56518781Sgibbs}
56618781Sgibbs
56718781Sgibbsint
56839217Sgibbsadv_test_external_lram(struct adv_softc* adv)
56918781Sgibbs{
57018781Sgibbs	u_int16_t	q_addr;
57118781Sgibbs	u_int16_t	saved_value;
57218781Sgibbs	int		success;
57318781Sgibbs
57418781Sgibbs	success = 0;
57518781Sgibbs
57618781Sgibbs	q_addr = ADV_QNO_TO_QADDR(241);
57718781Sgibbs	saved_value = adv_read_lram_16(adv, q_addr);
57818781Sgibbs	if (adv_write_and_verify_lram_16(adv, q_addr, 0x55AA) == 0) {
57918781Sgibbs		success = 1;
58018781Sgibbs		adv_write_lram_16(adv, q_addr, saved_value);
58118781Sgibbs	}
58218781Sgibbs	return (success);
58318781Sgibbs}
58418781Sgibbs
58518781Sgibbs
58618781Sgibbsint
58739217Sgibbsadv_init_lram_and_mcode(struct adv_softc *adv)
58818781Sgibbs{
58918781Sgibbs	u_int32_t	retval;
59039217Sgibbs
59118781Sgibbs	adv_disable_interrupt(adv);
59218781Sgibbs
59318781Sgibbs	adv_init_lram(adv);
59418781Sgibbs
59539217Sgibbs	retval = adv_load_microcode(adv, 0, (u_int16_t *)adv_mcode,
59639217Sgibbs				    adv_mcode_size);
59718781Sgibbs	if (retval != adv_mcode_chksum) {
59818781Sgibbs		printf("adv%d: Microcode download failed checksum!\n",
59918781Sgibbs		       adv->unit);
60018781Sgibbs		return (1);
60118781Sgibbs	}
60218781Sgibbs
60318781Sgibbs	if (adv_init_microcode_var(adv) != 0)
60418781Sgibbs		return (1);
60518781Sgibbs
60618781Sgibbs	adv_enable_interrupt(adv);
60718781Sgibbs	return (0);
60818781Sgibbs}
60918781Sgibbs
61018781Sgibbsu_int8_t
61139217Sgibbsadv_get_chip_irq(struct adv_softc *adv)
61218781Sgibbs{
61318781Sgibbs	u_int16_t	cfg_lsw;
61418781Sgibbs	u_int8_t	chip_irq;
61518781Sgibbs
61618781Sgibbs	cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW);
61718781Sgibbs
61818781Sgibbs	if ((adv->type & ADV_VL) != 0) {
61918781Sgibbs		chip_irq = (u_int8_t)(((cfg_lsw >> 2) & 0x07));
62018781Sgibbs		if ((chip_irq == 0) ||
62118781Sgibbs		    (chip_irq == 4) ||
62218781Sgibbs		    (chip_irq == 7)) {
62318781Sgibbs			return (0);
62418781Sgibbs		}
62518781Sgibbs		return (chip_irq + (ADV_MIN_IRQ_NO - 1));
62618781Sgibbs	}
62718781Sgibbs	chip_irq = (u_int8_t)(((cfg_lsw >> 2) & 0x03));
62818781Sgibbs	if (chip_irq == 3)
62918781Sgibbs		chip_irq += 2;
63018781Sgibbs	return (chip_irq + ADV_MIN_IRQ_NO);
63118781Sgibbs}
63218781Sgibbs
63318781Sgibbsu_int8_t
63439217Sgibbsadv_set_chip_irq(struct adv_softc *adv, u_int8_t irq_no)
63518781Sgibbs{
63618781Sgibbs	u_int16_t	cfg_lsw;
63718781Sgibbs
63818781Sgibbs	if ((adv->type & ADV_VL) != 0) {
63918781Sgibbs		if (irq_no != 0) {
64039217Sgibbs			if ((irq_no < ADV_MIN_IRQ_NO)
64139217Sgibbs			 || (irq_no > ADV_MAX_IRQ_NO)) {
64218781Sgibbs				irq_no = 0;
64318781Sgibbs			} else {
64418781Sgibbs				irq_no -= ADV_MIN_IRQ_NO - 1;
64518781Sgibbs			}
64618781Sgibbs		}
64718781Sgibbs		cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFE3;
64818781Sgibbs		cfg_lsw |= 0x0010;
64918781Sgibbs		ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw);
65018781Sgibbs		adv_toggle_irq_act(adv);
65118781Sgibbs
65218781Sgibbs		cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFE0;
65318781Sgibbs		cfg_lsw |= (irq_no & 0x07) << 2;
65418781Sgibbs		ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw);
65518781Sgibbs		adv_toggle_irq_act(adv);
65618781Sgibbs	} else if ((adv->type & ADV_ISA) != 0) {
65718781Sgibbs		if (irq_no == 15)
65818781Sgibbs			irq_no -= 2;
65918781Sgibbs		irq_no -= ADV_MIN_IRQ_NO;
66018781Sgibbs		cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFF3;
66118781Sgibbs		cfg_lsw |= (irq_no & 0x03) << 2;
66218781Sgibbs		ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw);
66318781Sgibbs	}
66418781Sgibbs	return (adv_get_chip_irq(adv));
66518781Sgibbs}
66618781Sgibbs
66739217Sgibbsvoid
66839217Sgibbsadv_set_chip_scsiid(struct adv_softc *adv, int new_id)
66939217Sgibbs{
67039217Sgibbs	u_int16_t cfg_lsw;
67139217Sgibbs
67239217Sgibbs	cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW);
67339217Sgibbs	if (ADV_CONFIG_SCSIID(cfg_lsw) == new_id)
67439217Sgibbs		return;
67539217Sgibbs    	cfg_lsw &= ~ADV_CFG_LSW_SCSIID;
67639217Sgibbs	cfg_lsw |= (new_id & ADV_MAX_TID) << ADV_CFG_LSW_SCSIID_SHIFT;
67739217Sgibbs	ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw);
67839217Sgibbs}
67939217Sgibbs
68018781Sgibbsint
68139217Sgibbsadv_execute_scsi_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq,
68239217Sgibbs		       u_int32_t datalen)
68318781Sgibbs{
68439217Sgibbs	struct		adv_target_transinfo* tinfo;
68539217Sgibbs	u_int32_t	*p_data_addr;
68639217Sgibbs	u_int32_t	*p_data_bcount;
68739217Sgibbs	int		disable_syn_offset_one_fix;
68818781Sgibbs	int		retval;
68918781Sgibbs	u_int		n_q_required;
69018781Sgibbs	u_int32_t	addr;
69118781Sgibbs	u_int8_t	sg_entry_cnt;
69218781Sgibbs	u_int8_t	target_ix;
69318781Sgibbs	u_int8_t	sg_entry_cnt_minus_one;
69418781Sgibbs	u_int8_t	tid_no;
69518781Sgibbs
69618781Sgibbs	scsiq->q1.q_no = 0;
69718781Sgibbs	retval = 1;  /* Default to error case */
69818781Sgibbs	target_ix = scsiq->q2.target_ix;
69918781Sgibbs	tid_no = ADV_TIX_TO_TID(target_ix);
70039217Sgibbs	tinfo = &adv->tinfo[tid_no];
70118781Sgibbs
70239217Sgibbs	if (scsiq->cdbptr[0] == REQUEST_SENSE) {
70339217Sgibbs		/* Renegotiate if appropriate. */
70439217Sgibbs		adv_set_syncrate(adv, /*struct cam_path */NULL,
70539217Sgibbs				 tid_no, /*period*/0, /*offset*/0,
70639217Sgibbs				 ADV_TRANS_CUR);
70739217Sgibbs		if (tinfo->current.period != tinfo->goal.period) {
70839217Sgibbs			adv_msgout_sdtr(adv, tinfo->goal.period,
70939217Sgibbs					tinfo->goal.offset);
71018781Sgibbs			scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
71118781Sgibbs		}
71218781Sgibbs	}
71318781Sgibbs
71418781Sgibbs	if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
71518781Sgibbs		sg_entry_cnt = scsiq->sg_head->entry_cnt;
71618781Sgibbs		sg_entry_cnt_minus_one = sg_entry_cnt - 1;
71718781Sgibbs
71818781Sgibbs#ifdef DIAGNOSTIC
71918781Sgibbs		if (sg_entry_cnt <= 1)
72039217Sgibbs			panic("adv_execute_scsi_queue: Queue "
72139217Sgibbs			      "with QC_SG_HEAD set but %d segs.", sg_entry_cnt);
72218781Sgibbs
72318781Sgibbs		if (sg_entry_cnt > ADV_MAX_SG_LIST)
72439217Sgibbs			panic("adv_execute_scsi_queue: "
72539217Sgibbs			      "Queue with too many segs.");
72618781Sgibbs
72755945Sgibbs		if ((adv->type & (ADV_ISA | ADV_VL | ADV_EISA)) != 0) {
72839505Sgibbs			int i;
72939505Sgibbs
73018781Sgibbs			for (i = 0; i < sg_entry_cnt_minus_one; i++) {
73118781Sgibbs				addr = scsiq->sg_head->sg_list[i].addr +
73218781Sgibbs				       scsiq->sg_head->sg_list[i].bytes;
73318781Sgibbs
73418781Sgibbs				if ((addr & 0x0003) != 0)
73539217Sgibbs					panic("adv_execute_scsi_queue: SG "
73639217Sgibbs					      "with odd address or byte count");
73718781Sgibbs			}
73818781Sgibbs		}
73918781Sgibbs#endif
74039217Sgibbs		p_data_addr =
74139217Sgibbs		    &scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].addr;
74239217Sgibbs		p_data_bcount =
74339217Sgibbs		    &scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].bytes;
74418781Sgibbs
74518781Sgibbs		n_q_required = adv_sgcount_to_qcount(sg_entry_cnt);
74618781Sgibbs		scsiq->sg_head->queue_cnt = n_q_required - 1;
74718781Sgibbs	} else {
74818781Sgibbs		p_data_addr = &scsiq->q1.data_addr;
74918781Sgibbs		p_data_bcount = &scsiq->q1.data_cnt;
75018781Sgibbs		n_q_required = 1;
75118781Sgibbs	}
75218781Sgibbs
75339217Sgibbs	disable_syn_offset_one_fix = FALSE;
75439217Sgibbs
75539217Sgibbs	if ((adv->fix_asyn_xfer & scsiq->q1.target_id) != 0
75639217Sgibbs	 && (adv->fix_asyn_xfer_always & scsiq->q1.target_id) == 0) {
75739217Sgibbs
75839217Sgibbs		if (datalen != 0) {
75939217Sgibbs			if (datalen < 512) {
76039217Sgibbs				disable_syn_offset_one_fix = TRUE;
76139217Sgibbs			} else {
76239217Sgibbs				if (scsiq->cdbptr[0] == INQUIRY
76339217Sgibbs				 || scsiq->cdbptr[0] == REQUEST_SENSE
76439217Sgibbs				 || scsiq->cdbptr[0] == READ_CAPACITY
76539217Sgibbs				 || scsiq->cdbptr[0] == MODE_SELECT_6
76639217Sgibbs				 || scsiq->cdbptr[0] == MODE_SENSE_6
76739217Sgibbs				 || scsiq->cdbptr[0] == MODE_SENSE_10
76839217Sgibbs				 || scsiq->cdbptr[0] == MODE_SELECT_10
76939217Sgibbs				 || scsiq->cdbptr[0] == READ_TOC) {
77039217Sgibbs					disable_syn_offset_one_fix = TRUE;
77118781Sgibbs				}
77218781Sgibbs			}
77318781Sgibbs		}
77418781Sgibbs	}
77539217Sgibbs
77639217Sgibbs	if (disable_syn_offset_one_fix) {
77739217Sgibbs		scsiq->q2.tag_code &=
77839217Sgibbs		    ~(MSG_SIMPLE_Q_TAG|MSG_HEAD_OF_Q_TAG|MSG_ORDERED_Q_TAG);
77939217Sgibbs		scsiq->q2.tag_code |= (ADV_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX
78039217Sgibbs				     | ADV_TAG_FLAG_DISABLE_DISCONNECT);
78139217Sgibbs	}
78239217Sgibbs
78339217Sgibbs	if ((adv->bug_fix_control & ADV_BUG_FIX_IF_NOT_DWB) != 0
78439217Sgibbs	 && (scsiq->cdbptr[0] == READ_10 || scsiq->cdbptr[0] == READ_6)) {
78539217Sgibbs		u_int8_t extra_bytes;
78639217Sgibbs
78739217Sgibbs		addr = *p_data_addr + *p_data_bcount;
78839217Sgibbs		extra_bytes = addr & 0x0003;
78939217Sgibbs		if (extra_bytes != 0
79039217Sgibbs		 && ((scsiq->q1.cntl & QC_SG_HEAD) != 0
79139217Sgibbs		  || (scsiq->q1.data_cnt & 0x01FF) == 0)) {
79239217Sgibbs			scsiq->q2.tag_code |= ADV_TAG_FLAG_EXTRA_BYTES;
79339217Sgibbs			scsiq->q1.extra_bytes = extra_bytes;
79439217Sgibbs			*p_data_bcount -= extra_bytes;
79539217Sgibbs		}
79639217Sgibbs	}
79739217Sgibbs
79818781Sgibbs	if ((adv_get_num_free_queues(adv, n_q_required) >= n_q_required)
79939217Sgibbs	 || ((scsiq->q1.cntl & QC_URGENT) != 0))
80018781Sgibbs		retval = adv_send_scsi_queue(adv, scsiq, n_q_required);
80118781Sgibbs
80218781Sgibbs	return (retval);
80318781Sgibbs}
80418781Sgibbs
80518781Sgibbs
80618781Sgibbsu_int8_t
80739217Sgibbsadv_copy_lram_doneq(struct adv_softc *adv, u_int16_t q_addr,
80839217Sgibbs		    struct adv_q_done_info *scsiq, u_int32_t max_dma_count)
80918781Sgibbs{
81039217Sgibbs	u_int16_t val;
81139217Sgibbs	u_int8_t  sg_queue_cnt;
81218781Sgibbs
81318781Sgibbs	adv_get_q_info(adv, q_addr + ADV_SCSIQ_DONE_INFO_BEG,
81418781Sgibbs		       (u_int16_t *)scsiq,
81518781Sgibbs		       (sizeof(scsiq->d2) + sizeof(scsiq->d3)) / 2);
81618781Sgibbs
81718781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
81818781Sgibbs	adv_adj_endian_qdone_info(scsiq);
81918781Sgibbs#endif
82018781Sgibbs
82118781Sgibbs	val = adv_read_lram_16(adv, q_addr + ADV_SCSIQ_B_STATUS);
82218781Sgibbs	scsiq->q_status = val & 0xFF;
82318781Sgibbs	scsiq->q_no = (val >> 8) & 0XFF;
82418781Sgibbs
82518781Sgibbs	val = adv_read_lram_16(adv, q_addr + ADV_SCSIQ_B_CNTL);
82618781Sgibbs	scsiq->cntl = val & 0xFF;
82718781Sgibbs	sg_queue_cnt = (val >> 8) & 0xFF;
82818781Sgibbs
82918781Sgibbs	val = adv_read_lram_16(adv,q_addr + ADV_SCSIQ_B_SENSE_LEN);
83018781Sgibbs	scsiq->sense_len = val & 0xFF;
83139217Sgibbs	scsiq->extra_bytes = (val >> 8) & 0xFF;
83218781Sgibbs
83340133Sgibbs	/*
83455945Sgibbs	 * Due to a bug in accessing LRAM on the 940UA, the residual
83555945Sgibbs	 * is split into separate high and low 16bit quantities.
83640133Sgibbs	 */
83739217Sgibbs	scsiq->remain_bytes =
83840133Sgibbs	    adv_read_lram_16(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_CNT);
83955945Sgibbs	scsiq->remain_bytes |=
84055945Sgibbs	    adv_read_lram_16(adv, q_addr + ADV_SCSIQ_W_ALT_DC1) << 16;
84155945Sgibbs
84218781Sgibbs	/*
84318781Sgibbs	 * XXX Is this just a safeguard or will the counter really
84418781Sgibbs	 * have bogus upper bits?
84518781Sgibbs	 */
84618781Sgibbs	scsiq->remain_bytes &= max_dma_count;
84718781Sgibbs
84818781Sgibbs	return (sg_queue_cnt);
84918781Sgibbs}
85018781Sgibbs
85118781Sgibbsint
85239217Sgibbsadv_start_chip(struct adv_softc *adv)
85318781Sgibbs{
85439217Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, 0);
85539217Sgibbs	if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) != 0)
85639217Sgibbs		return (0);
85739217Sgibbs	return (1);
85839217Sgibbs}
85939217Sgibbs
86039217Sgibbsint
86139217Sgibbsadv_stop_execution(struct adv_softc *adv)
86239217Sgibbs{
86318781Sgibbs	int count;
86418781Sgibbs
86518781Sgibbs	count = 0;
86618781Sgibbs	if (adv_read_lram_8(adv, ADV_STOP_CODE_B) == 0) {
86718781Sgibbs		adv_write_lram_8(adv, ADV_STOP_CODE_B,
86818781Sgibbs				 ADV_STOP_REQ_RISC_STOP);
86918781Sgibbs		do {
87018781Sgibbs			if (adv_read_lram_8(adv, ADV_STOP_CODE_B) &
87118781Sgibbs				ADV_STOP_ACK_RISC_STOP) {
87218781Sgibbs				return (1);
87318781Sgibbs			}
87418781Sgibbs			DELAY(1000);
87518781Sgibbs		} while (count++ < 20);
87618781Sgibbs	}
87718781Sgibbs	return (0);
87818781Sgibbs}
87918781Sgibbs
88018781Sgibbsint
88139217Sgibbsadv_is_chip_halted(struct adv_softc *adv)
88218781Sgibbs{
88318781Sgibbs	if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) != 0) {
88418781Sgibbs		if ((ADV_INB(adv, ADV_CHIP_CTRL) & ADV_CC_HALT) != 0) {
88518781Sgibbs			return (1);
88618781Sgibbs		}
88718781Sgibbs	}
88818781Sgibbs	return (0);
88918781Sgibbs}
89018781Sgibbs
89118781Sgibbs/*
89218781Sgibbs * XXX The numeric constants and the loops in this routine
89318781Sgibbs * need to be documented.
89418781Sgibbs */
89518781Sgibbsvoid
89639217Sgibbsadv_ack_interrupt(struct adv_softc *adv)
89718781Sgibbs{
89818781Sgibbs	u_int8_t	host_flag;
89918781Sgibbs	u_int8_t	risc_flag;
90018781Sgibbs	int		loop;
90118781Sgibbs
90218781Sgibbs	loop = 0;
90318781Sgibbs	do {
90418781Sgibbs		risc_flag = adv_read_lram_8(adv, ADVV_RISC_FLAG_B);
90518781Sgibbs		if (loop++ > 0x7FFF) {
90618781Sgibbs			break;
90718781Sgibbs		}
90818781Sgibbs	} while ((risc_flag & ADV_RISC_FLAG_GEN_INT) != 0);
90918781Sgibbs
91018781Sgibbs	host_flag = adv_read_lram_8(adv, ADVV_HOST_FLAG_B);
91118781Sgibbs	adv_write_lram_8(adv, ADVV_HOST_FLAG_B,
91218781Sgibbs			 host_flag | ADV_HOST_FLAG_ACK_INT);
91318781Sgibbs
91418781Sgibbs	ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_INT_ACK);
91518781Sgibbs	loop = 0;
91618781Sgibbs	while (ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_INT_PENDING) {
91718781Sgibbs		ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_INT_ACK);
91818781Sgibbs		if (loop++ > 3) {
91918781Sgibbs			break;
92018781Sgibbs		}
92118781Sgibbs	}
92218781Sgibbs
92318781Sgibbs	adv_write_lram_8(adv, ADVV_HOST_FLAG_B, host_flag);
92418781Sgibbs}
92518781Sgibbs
92618781Sgibbs/*
92718781Sgibbs * Handle all conditions that may halt the chip waiting
92818781Sgibbs * for us to intervene.
92918781Sgibbs */
93018781Sgibbsvoid
93139217Sgibbsadv_isr_chip_halted(struct adv_softc *adv)
93218781Sgibbs{
93318781Sgibbs	u_int16_t	  int_halt_code;
93439217Sgibbs	u_int16_t	  halt_q_addr;
93539217Sgibbs	target_bit_vector target_mask;
93639217Sgibbs	target_bit_vector scsi_busy;
93718781Sgibbs	u_int8_t	  halt_qp;
93818781Sgibbs	u_int8_t	  target_ix;
93918781Sgibbs	u_int8_t	  q_cntl;
94018781Sgibbs	u_int8_t	  tid_no;
94118781Sgibbs
94218781Sgibbs	int_halt_code = adv_read_lram_16(adv, ADVV_HALTCODE_W);
94318781Sgibbs	halt_qp = adv_read_lram_8(adv, ADVV_CURCDB_B);
94418781Sgibbs	halt_q_addr = ADV_QNO_TO_QADDR(halt_qp);
94518781Sgibbs	target_ix = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_TARGET_IX);
94618781Sgibbs	q_cntl = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL);
94718781Sgibbs	tid_no = ADV_TIX_TO_TID(target_ix);
94839217Sgibbs	target_mask = ADV_TID_TO_TARGET_MASK(tid_no);
94939217Sgibbs	if (int_halt_code == ADV_HALT_DISABLE_ASYN_USE_SYN_FIX) {
95018781Sgibbs		/*
95139217Sgibbs		 * Temporarily disable the async fix by removing
95239217Sgibbs		 * this target from the list of affected targets,
95339217Sgibbs		 * setting our async rate, and then putting us
95439217Sgibbs		 * back into the mask.
95518781Sgibbs		 */
95639217Sgibbs		adv->fix_asyn_xfer &= ~target_mask;
95739217Sgibbs		adv_set_syncrate(adv, /*struct cam_path */NULL,
95839217Sgibbs				 tid_no, /*period*/0, /*offset*/0,
95939217Sgibbs				 ADV_TRANS_ACTIVE);
96039217Sgibbs		adv->fix_asyn_xfer |= target_mask;
96139217Sgibbs	} else if (int_halt_code == ADV_HALT_ENABLE_ASYN_USE_SYN_FIX) {
96239217Sgibbs		adv_set_syncrate(adv, /*struct cam_path */NULL,
96339217Sgibbs				 tid_no, /*period*/0, /*offset*/0,
96439217Sgibbs				 ADV_TRANS_ACTIVE);
96539217Sgibbs	} else if (int_halt_code == ADV_HALT_EXTMSG_IN) {
96639217Sgibbs		adv_handle_extmsg_in(adv, halt_q_addr, q_cntl,
96739217Sgibbs				     target_mask, tid_no);
96818781Sgibbs	} else if (int_halt_code == ADV_HALT_CHK_CONDITION) {
96955945Sgibbs		struct	  adv_target_transinfo* tinfo;
97055945Sgibbs		union	  ccb *ccb;
97155945Sgibbs		u_int32_t cinfo_index;
97255945Sgibbs		u_int8_t  tag_code;
97355945Sgibbs		u_int8_t  q_status;
97418781Sgibbs
97539217Sgibbs		tinfo = &adv->tinfo[tid_no];
97618781Sgibbs		q_cntl |= QC_REQ_SENSE;
97718781Sgibbs
97839217Sgibbs		/* Renegotiate if appropriate. */
97939217Sgibbs		adv_set_syncrate(adv, /*struct cam_path */NULL,
98039217Sgibbs				 tid_no, /*period*/0, /*offset*/0,
98139217Sgibbs				 ADV_TRANS_CUR);
98239217Sgibbs		if (tinfo->current.period != tinfo->goal.period) {
98339217Sgibbs			adv_msgout_sdtr(adv, tinfo->goal.period,
98439217Sgibbs					tinfo->goal.offset);
98518781Sgibbs			q_cntl |= QC_MSG_OUT;
98618781Sgibbs		}
98718781Sgibbs		adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl);
98818781Sgibbs
98918781Sgibbs		/* Don't tag request sense commands */
99039217Sgibbs		tag_code = adv_read_lram_8(adv,
99139217Sgibbs					   halt_q_addr + ADV_SCSIQ_B_TAG_CODE);
99239217Sgibbs		tag_code &=
99339217Sgibbs		    ~(MSG_SIMPLE_Q_TAG|MSG_HEAD_OF_Q_TAG|MSG_ORDERED_Q_TAG);
99418781Sgibbs
99539217Sgibbs		if ((adv->fix_asyn_xfer & target_mask) != 0
99639217Sgibbs		 && (adv->fix_asyn_xfer_always & target_mask) == 0) {
99739217Sgibbs			tag_code |= (ADV_TAG_FLAG_DISABLE_DISCONNECT
99839217Sgibbs				 | ADV_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
99939217Sgibbs		}
100039217Sgibbs		adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_TAG_CODE,
100139217Sgibbs				 tag_code);
100239217Sgibbs		q_status = adv_read_lram_8(adv,
100339217Sgibbs					   halt_q_addr + ADV_SCSIQ_B_STATUS);
100418781Sgibbs		q_status |= (QS_READY | QS_BUSY);
100539217Sgibbs		adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_STATUS,
100639217Sgibbs				 q_status);
100739217Sgibbs		/*
100839217Sgibbs		 * Freeze the devq until we can handle the sense condition.
100939217Sgibbs		 */
101055945Sgibbs		cinfo_index =
101155945Sgibbs		    adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX);
101255945Sgibbs		ccb = adv->ccb_infos[cinfo_index].ccb;
101339217Sgibbs		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
101439217Sgibbs		ccb->ccb_h.status |= CAM_DEV_QFRZN;
101539217Sgibbs		adv_abort_ccb(adv, tid_no, ADV_TIX_TO_LUN(target_ix),
101639217Sgibbs			      /*ccb*/NULL, CAM_REQUEUE_REQ,
101739217Sgibbs			      /*queued_only*/TRUE);
101818781Sgibbs		scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B);
101939217Sgibbs		scsi_busy &= ~target_mask;
102018781Sgibbs		adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy);
102145846Sgibbs		/*
102245846Sgibbs		 * Ensure we have enough time to actually
102345846Sgibbs		 * retrieve the sense.
102445846Sgibbs		 */
102545846Sgibbs		untimeout(adv_timeout, (caddr_t)ccb, ccb->ccb_h.timeout_ch);
102645846Sgibbs		ccb->ccb_h.timeout_ch =
102745846Sgibbs		    timeout(adv_timeout, (caddr_t)ccb, 5 * hz);
102818781Sgibbs	} else if (int_halt_code == ADV_HALT_SDTR_REJECTED) {
102939217Sgibbs		struct	ext_msg out_msg;
103018781Sgibbs
103118781Sgibbs		adv_read_lram_16_multi(adv, ADVV_MSGOUT_BEG,
103218781Sgibbs				       (u_int16_t *) &out_msg,
103318781Sgibbs				       sizeof(out_msg)/2);
103418781Sgibbs
103539217Sgibbs		if ((out_msg.msg_type == MSG_EXTENDED)
103639217Sgibbs		 && (out_msg.msg_len == MSG_EXT_SDTR_LEN)
103739217Sgibbs		 && (out_msg.msg_req == MSG_EXT_SDTR)) {
103818781Sgibbs
103939217Sgibbs			/* Revert to Async */
104039217Sgibbs			adv_set_syncrate(adv, /*struct cam_path */NULL,
104139217Sgibbs					 tid_no, /*period*/0, /*offset*/0,
104239217Sgibbs					 ADV_TRANS_GOAL|ADV_TRANS_ACTIVE);
104318781Sgibbs		}
104418781Sgibbs		q_cntl &= ~QC_MSG_OUT;
104518781Sgibbs		adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl);
104618781Sgibbs	} else if (int_halt_code == ADV_HALT_SS_QUEUE_FULL) {
104739217Sgibbs		u_int8_t scsi_status;
104839217Sgibbs		union ccb *ccb;
104955945Sgibbs		u_int32_t cinfo_index;
105039217Sgibbs
105139217Sgibbs		scsi_status = adv_read_lram_8(adv, halt_q_addr
105239217Sgibbs					      + ADV_SCSIQ_SCSI_STATUS);
105355945Sgibbs		cinfo_index =
105455945Sgibbs		    adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX);
105555945Sgibbs		ccb = adv->ccb_infos[cinfo_index].ccb;
105639217Sgibbs		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
105740733Sgibbs		ccb->ccb_h.status |= CAM_DEV_QFRZN|CAM_SCSI_STATUS_ERROR;
105840733Sgibbs		ccb->csio.scsi_status = SCSI_STATUS_QUEUE_FULL;
105939217Sgibbs		adv_abort_ccb(adv, tid_no, ADV_TIX_TO_LUN(target_ix),
106039217Sgibbs			      /*ccb*/NULL, CAM_REQUEUE_REQ,
106139217Sgibbs			      /*queued_only*/TRUE);
106239217Sgibbs		scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B);
106339217Sgibbs		scsi_busy &= ~target_mask;
106439217Sgibbs		adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy);
106555945Sgibbs	} else {
106655945Sgibbs		printf("Unhandled Halt Code %x\n", int_halt_code);
106739217Sgibbs	}
106839217Sgibbs	adv_write_lram_16(adv, ADVV_HALTCODE_W, 0);
106939217Sgibbs}
107018781Sgibbs
107139217Sgibbsvoid
107239217Sgibbsadv_sdtr_to_period_offset(struct adv_softc *adv,
107339217Sgibbs			  u_int8_t sync_data, u_int8_t *period,
107439217Sgibbs			  u_int8_t *offset, int tid)
107539217Sgibbs{
107639217Sgibbs	if (adv->fix_asyn_xfer & ADV_TID_TO_TARGET_MASK(tid)
107739217Sgibbs	 && (sync_data == ASYN_SDTR_DATA_FIX_PCI_REV_AB)) {
107839217Sgibbs		*period = *offset = 0;
107939217Sgibbs	} else {
108039217Sgibbs		*period = adv->sdtr_period_tbl[((sync_data >> 4) & 0xF)];
108139217Sgibbs		*offset = sync_data & 0xF;
108239217Sgibbs	}
108339217Sgibbs}
108439217Sgibbs
108539217Sgibbsvoid
108639217Sgibbsadv_set_syncrate(struct adv_softc *adv, struct cam_path *path,
108739217Sgibbs		 u_int tid, u_int period, u_int offset, u_int type)
108839217Sgibbs{
108939217Sgibbs	struct adv_target_transinfo* tinfo;
109039217Sgibbs	u_int old_period;
109139217Sgibbs	u_int old_offset;
109239217Sgibbs	u_int8_t sdtr_data;
109339217Sgibbs
109439217Sgibbs	tinfo = &adv->tinfo[tid];
109539217Sgibbs
109639217Sgibbs	/* Filter our input */
109739217Sgibbs	sdtr_data = adv_period_offset_to_sdtr(adv, &period,
109839217Sgibbs					      &offset, tid);
109939217Sgibbs
110039217Sgibbs	old_period = tinfo->current.period;
110139217Sgibbs	old_offset = tinfo->current.offset;
110239217Sgibbs
110339217Sgibbs	if ((type & ADV_TRANS_CUR) != 0
110439217Sgibbs	 && ((old_period != period || old_offset != offset)
110539217Sgibbs	  || period == 0 || offset == 0) /*Changes in asyn fix settings*/) {
110639217Sgibbs		int s;
110739217Sgibbs		int halted;
110839217Sgibbs
110939217Sgibbs		s = splcam();
111039217Sgibbs		halted = adv_is_chip_halted(adv);
111139217Sgibbs		if (halted == 0)
111239217Sgibbs			/* Must halt the chip first */
111339217Sgibbs			adv_host_req_chip_halt(adv);
111439217Sgibbs
111539217Sgibbs		/* Update current hardware settings */
111639217Sgibbs		adv_set_sdtr_reg_at_id(adv, tid, sdtr_data);
111739217Sgibbs
111818781Sgibbs		/*
111939217Sgibbs		 * If a target can run in sync mode, we don't need
112039217Sgibbs		 * to check it for sync problems.
112118781Sgibbs		 */
112239217Sgibbs		if (offset != 0)
112339217Sgibbs			adv->fix_asyn_xfer &= ~ADV_TID_TO_TARGET_MASK(tid);
112418781Sgibbs
112539217Sgibbs		if (halted == 0)
112639217Sgibbs			/* Start the chip again */
112739217Sgibbs			adv_start_chip(adv);
112818781Sgibbs
112939217Sgibbs		splx(s);
113039217Sgibbs		tinfo->current.period = period;
113139217Sgibbs		tinfo->current.offset = offset;
113239217Sgibbs
113339217Sgibbs		if (path != NULL) {
113439217Sgibbs			/*
113539217Sgibbs			 * Tell the SCSI layer about the
113639217Sgibbs			 * new transfer parameters.
113739217Sgibbs			 */
113839217Sgibbs			struct	ccb_trans_settings neg;
113939217Sgibbs
114039217Sgibbs			neg.sync_period = period;
114139217Sgibbs			neg.sync_offset = offset;
114239217Sgibbs			neg.valid = CCB_TRANS_SYNC_RATE_VALID
114339217Sgibbs				  | CCB_TRANS_SYNC_OFFSET_VALID;
114439217Sgibbs			xpt_setup_ccb(&neg.ccb_h, path, /*priority*/1);
114539217Sgibbs			xpt_async(AC_TRANSFER_NEG, path, &neg);
114639217Sgibbs		}
114739217Sgibbs	}
114839217Sgibbs
114939217Sgibbs	if ((type & ADV_TRANS_GOAL) != 0) {
115039217Sgibbs		tinfo->goal.period = period;
115139217Sgibbs		tinfo->goal.offset = offset;
115239217Sgibbs	}
115339217Sgibbs
115439217Sgibbs	if ((type & ADV_TRANS_USER) != 0) {
115539217Sgibbs		tinfo->user.period = period;
115639217Sgibbs		tinfo->user.offset = offset;
115739217Sgibbs	}
115839217Sgibbs}
115939217Sgibbs
116039217Sgibbsu_int8_t
116139217Sgibbsadv_period_offset_to_sdtr(struct adv_softc *adv, u_int *period,
116239217Sgibbs			  u_int *offset, int tid)
116339217Sgibbs{
116439217Sgibbs	u_int i;
116539217Sgibbs	u_int dummy_offset;
116639217Sgibbs	u_int dummy_period;
116739217Sgibbs
116839217Sgibbs	if (offset == NULL) {
116939217Sgibbs		dummy_offset = 0;
117039217Sgibbs		offset = &dummy_offset;
117139217Sgibbs	}
117239217Sgibbs
117339217Sgibbs	if (period == NULL) {
117439217Sgibbs		dummy_period = 0;
117539217Sgibbs		period = &dummy_period;
117639217Sgibbs	}
117739217Sgibbs
117839217Sgibbs	*offset = MIN(ADV_SYN_MAX_OFFSET, *offset);
117939217Sgibbs	if (*period != 0 && *offset != 0) {
118039217Sgibbs		for (i = 0; i < adv->sdtr_period_tbl_size; i++) {
118139217Sgibbs			if (*period <= adv->sdtr_period_tbl[i]) {
118239217Sgibbs				/*
118339217Sgibbs				 * When responding to a target that requests
118439217Sgibbs				 * sync, the requested  rate may fall between
118539217Sgibbs				 * two rates that we can output, but still be
118639217Sgibbs				 * a rate that we can receive.  Because of this,
118739217Sgibbs				 * we want to respond to the target with
118839217Sgibbs				 * the same rate that it sent to us even
118939217Sgibbs				 * if the period we use to send data to it
119039217Sgibbs				 * is lower.  Only lower the response period
119139217Sgibbs				 * if we must.
119239217Sgibbs				 */
119339217Sgibbs				if (i == 0 /* Our maximum rate */)
119439217Sgibbs					*period = adv->sdtr_period_tbl[0];
119539217Sgibbs				return ((i << 4) | *offset);
119618781Sgibbs			}
119718781Sgibbs		}
119818781Sgibbs	}
119939217Sgibbs
120039217Sgibbs	/* Must go async */
120139217Sgibbs	*period = 0;
120239217Sgibbs	*offset = 0;
120339217Sgibbs	if (adv->fix_asyn_xfer & ADV_TID_TO_TARGET_MASK(tid))
120439217Sgibbs		return (ASYN_SDTR_DATA_FIX_PCI_REV_AB);
120539217Sgibbs	return (0);
120618781Sgibbs}
120718781Sgibbs
120818781Sgibbs/* Internal Routines */
120918781Sgibbs
121018781Sgibbsstatic void
121139217Sgibbsadv_read_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr,
121239217Sgibbs		       u_int16_t *buffer, int count)
121318781Sgibbs{
121418781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
121518781Sgibbs	ADV_INSW(adv, ADV_LRAM_DATA, buffer, count);
121618781Sgibbs}
121718781Sgibbs
121818781Sgibbsstatic void
121939217Sgibbsadv_write_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr,
122039217Sgibbs			u_int16_t *buffer, int count)
122118781Sgibbs{
122218781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
122318781Sgibbs	ADV_OUTSW(adv, ADV_LRAM_DATA, buffer, count);
122418781Sgibbs}
122518781Sgibbs
122618781Sgibbsstatic void
122739217Sgibbsadv_mset_lram_16(struct adv_softc *adv, u_int16_t s_addr,
122839217Sgibbs		 u_int16_t set_value, int count)
122918781Sgibbs{
123018781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
123139217Sgibbs	bus_space_set_multi_2(adv->tag, adv->bsh, ADV_LRAM_DATA,
123239217Sgibbs			      set_value, count);
123318781Sgibbs}
123418781Sgibbs
123518781Sgibbsstatic u_int32_t
123639217Sgibbsadv_msum_lram_16(struct adv_softc *adv, u_int16_t s_addr, int count)
123718781Sgibbs{
123818781Sgibbs	u_int32_t	sum;
123918781Sgibbs	int		i;
124018781Sgibbs
124118781Sgibbs	sum = 0;
124239217Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
124339217Sgibbs	for (i = 0; i < count; i++)
124439217Sgibbs		sum += ADV_INW(adv, ADV_LRAM_DATA);
124518781Sgibbs	return (sum);
124618781Sgibbs}
124718781Sgibbs
124818781Sgibbsstatic int
124939217Sgibbsadv_write_and_verify_lram_16(struct adv_softc *adv, u_int16_t addr,
125039217Sgibbs			     u_int16_t value)
125118781Sgibbs{
125218781Sgibbs	int	retval;
125318781Sgibbs
125418781Sgibbs	retval = 0;
125518781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
125618781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, value);
125739217Sgibbs	DELAY(10000);
125818781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
125918781Sgibbs	if (value != ADV_INW(adv, ADV_LRAM_DATA))
126018781Sgibbs		retval = 1;
126118781Sgibbs	return (retval);
126218781Sgibbs}
126318781Sgibbs
126418781Sgibbsstatic u_int32_t
126539217Sgibbsadv_read_lram_32(struct adv_softc *adv, u_int16_t addr)
126618781Sgibbs{
126718781Sgibbs	u_int16_t           val_low, val_high;
126818781Sgibbs
126918781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
127018781Sgibbs
127118781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
127218781Sgibbs	val_high = ADV_INW(adv, ADV_LRAM_DATA);
127318781Sgibbs	val_low = ADV_INW(adv, ADV_LRAM_DATA);
127418781Sgibbs#else
127518781Sgibbs	val_low = ADV_INW(adv, ADV_LRAM_DATA);
127618781Sgibbs	val_high = ADV_INW(adv, ADV_LRAM_DATA);
127718781Sgibbs#endif
127818781Sgibbs
127918781Sgibbs	return (((u_int32_t)val_high << 16) | (u_int32_t)val_low);
128018781Sgibbs}
128118781Sgibbs
128218781Sgibbsstatic void
128339217Sgibbsadv_write_lram_32(struct adv_softc *adv, u_int16_t addr, u_int32_t value)
128418781Sgibbs{
128518781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
128618781Sgibbs
128718781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
128818781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)((value >> 16) & 0xFFFF));
128918781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)(value & 0xFFFF));
129018781Sgibbs#else
129118781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)(value & 0xFFFF));
129218781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)((value >> 16) & 0xFFFF));
129318781Sgibbs#endif
129418781Sgibbs}
129518781Sgibbs
129618781Sgibbsstatic void
129739217Sgibbsadv_write_lram_32_multi(struct adv_softc *adv, u_int16_t s_addr,
129839217Sgibbs			u_int32_t *buffer, int count)
129918781Sgibbs{
130018781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
130139217Sgibbs	ADV_OUTSW(adv, ADV_LRAM_DATA, (u_int16_t *)buffer, count * 2);
130218781Sgibbs}
130318781Sgibbs
130418781Sgibbsstatic u_int16_t
130539217Sgibbsadv_read_eeprom_16(struct adv_softc *adv, u_int8_t addr)
130618781Sgibbs{
130718781Sgibbs	u_int16_t read_wval;
130818781Sgibbs	u_int8_t  cmd_reg;
130918781Sgibbs
131018781Sgibbs	adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_DISABLE);
131118781Sgibbs	DELAY(1000);
131218781Sgibbs	cmd_reg = addr | ADV_EEPROM_CMD_READ;
131318781Sgibbs	adv_write_eeprom_cmd_reg(adv, cmd_reg);
131418781Sgibbs	DELAY(1000);
131518781Sgibbs	read_wval = ADV_INW(adv, ADV_EEPROM_DATA);
131618781Sgibbs	DELAY(1000);
131718781Sgibbs	return (read_wval);
131818781Sgibbs}
131918781Sgibbs
132018781Sgibbsstatic u_int16_t
132139217Sgibbsadv_write_eeprom_16(struct adv_softc *adv, u_int8_t addr, u_int16_t value)
132218781Sgibbs{
132318781Sgibbs	u_int16_t	read_value;
132418781Sgibbs
132518781Sgibbs	read_value = adv_read_eeprom_16(adv, addr);
132618781Sgibbs	if (read_value != value) {
132718781Sgibbs		adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_ENABLE);
132818781Sgibbs		DELAY(1000);
132918781Sgibbs
133018781Sgibbs		ADV_OUTW(adv, ADV_EEPROM_DATA, value);
133118781Sgibbs		DELAY(1000);
133218781Sgibbs
133318781Sgibbs		adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE | addr);
133418781Sgibbs		DELAY(20 * 1000);
133518781Sgibbs
133618781Sgibbs		adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_DISABLE);
133718781Sgibbs		DELAY(1000);
133818781Sgibbs		read_value = adv_read_eeprom_16(adv, addr);
133918781Sgibbs	}
134018781Sgibbs	return (read_value);
134118781Sgibbs}
134218781Sgibbs
134318781Sgibbsstatic int
134439217Sgibbsadv_write_eeprom_cmd_reg(struct adv_softc *adv, u_int8_t cmd_reg)
134518781Sgibbs{
134618781Sgibbs	u_int8_t read_back;
134718781Sgibbs	int	 retry;
134818781Sgibbs
134918781Sgibbs	retry = 0;
135018781Sgibbs	while (1) {
135118781Sgibbs		ADV_OUTB(adv, ADV_EEPROM_CMD, cmd_reg);
135218781Sgibbs		DELAY(1000);
135318781Sgibbs		read_back = ADV_INB(adv, ADV_EEPROM_CMD);
135418781Sgibbs		if (read_back == cmd_reg) {
135518781Sgibbs			return (1);
135618781Sgibbs		}
135718781Sgibbs		if (retry++ > ADV_EEPROM_MAX_RETRY) {
135818781Sgibbs			return (0);
135918781Sgibbs		}
136018781Sgibbs	}
136118781Sgibbs}
136218781Sgibbs
136318781Sgibbsstatic int
136439217Sgibbsadv_set_eeprom_config_once(struct adv_softc *adv,
136539217Sgibbs			   struct adv_eeprom_config *eeprom_config)
136618781Sgibbs{
136718781Sgibbs	int		n_error;
136818781Sgibbs	u_int16_t	*wbuf;
136918781Sgibbs	u_int16_t	sum;
137018781Sgibbs	u_int8_t	s_addr;
137118781Sgibbs	u_int8_t	cfg_beg;
137218781Sgibbs	u_int8_t	cfg_end;
137318781Sgibbs
137418781Sgibbs	wbuf = (u_int16_t *)eeprom_config;
137518781Sgibbs	n_error = 0;
137618781Sgibbs	sum = 0;
137718781Sgibbs	for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
137818781Sgibbs		sum += *wbuf;
137918781Sgibbs		if (*wbuf != adv_write_eeprom_16(adv, s_addr, *wbuf)) {
138018781Sgibbs			n_error++;
138118781Sgibbs		}
138218781Sgibbs	}
138318781Sgibbs	if (adv->type & ADV_VL) {
138418781Sgibbs		cfg_beg = ADV_EEPROM_CFG_BEG_VL;
138518781Sgibbs		cfg_end = ADV_EEPROM_MAX_ADDR_VL;
138618781Sgibbs	} else {
138718781Sgibbs		cfg_beg = ADV_EEPROM_CFG_BEG;
138818781Sgibbs		cfg_end = ADV_EEPROM_MAX_ADDR;
138918781Sgibbs	}
139018781Sgibbs
139118781Sgibbs	for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
139218781Sgibbs		sum += *wbuf;
139318781Sgibbs		if (*wbuf != adv_write_eeprom_16(adv, s_addr, *wbuf)) {
139418781Sgibbs			n_error++;
139518781Sgibbs		}
139618781Sgibbs	}
139718781Sgibbs	*wbuf = sum;
139818781Sgibbs	if (sum != adv_write_eeprom_16(adv, s_addr, sum)) {
139918781Sgibbs		n_error++;
140018781Sgibbs	}
140118781Sgibbs	wbuf = (u_int16_t *)eeprom_config;
140218781Sgibbs	for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
140318781Sgibbs		if (*wbuf != adv_read_eeprom_16(adv, s_addr)) {
140418781Sgibbs			n_error++;
140518781Sgibbs		}
140618781Sgibbs	}
140718781Sgibbs	for (s_addr = cfg_beg; s_addr <= cfg_end; s_addr++, wbuf++) {
140818781Sgibbs		if (*wbuf != adv_read_eeprom_16(adv, s_addr)) {
140918781Sgibbs			n_error++;
141018781Sgibbs		}
141118781Sgibbs	}
141218781Sgibbs	return (n_error);
141318781Sgibbs}
141418781Sgibbs
141518781Sgibbsstatic u_int32_t
141639217Sgibbsadv_load_microcode(struct adv_softc *adv, u_int16_t s_addr,
141739217Sgibbs		   u_int16_t *mcode_buf, u_int16_t mcode_size)
141818781Sgibbs{
141939217Sgibbs	u_int32_t chksum;
142039217Sgibbs	u_int16_t mcode_lram_size;
142139217Sgibbs	u_int16_t mcode_chksum;
142218781Sgibbs
142318781Sgibbs	mcode_lram_size = mcode_size >> 1;
142418781Sgibbs	/* XXX Why zero the memory just before you write the whole thing?? */
142539217Sgibbs	adv_mset_lram_16(adv, s_addr, 0, mcode_lram_size);
142618781Sgibbs	adv_write_lram_16_multi(adv, s_addr, mcode_buf, mcode_lram_size);
142718781Sgibbs
142818781Sgibbs	chksum = adv_msum_lram_16(adv, s_addr, mcode_lram_size);
142918781Sgibbs	mcode_chksum = (u_int16_t)adv_msum_lram_16(adv, ADV_CODE_SEC_BEG,
143039217Sgibbs						   ((mcode_size - s_addr
143139217Sgibbs						     - ADV_CODE_SEC_BEG) >> 1));
143218781Sgibbs	adv_write_lram_16(adv, ADVV_MCODE_CHKSUM_W, mcode_chksum);
143318781Sgibbs	adv_write_lram_16(adv, ADVV_MCODE_SIZE_W, mcode_size);
143418781Sgibbs	return (chksum);
143518781Sgibbs}
143618781Sgibbs
143718781Sgibbsstatic void
143839217Sgibbsadv_reinit_lram(struct adv_softc *adv) {
143939217Sgibbs	adv_init_lram(adv);
144039217Sgibbs	adv_init_qlink_var(adv);
144139217Sgibbs}
144239217Sgibbs
144339217Sgibbsstatic void
144439217Sgibbsadv_init_lram(struct adv_softc *adv)
144518781Sgibbs{
144639217Sgibbs	u_int8_t  i;
144739217Sgibbs	u_int16_t s_addr;
144818781Sgibbs
144918781Sgibbs	adv_mset_lram_16(adv, ADV_QADR_BEG, 0,
145039217Sgibbs			 (((adv->max_openings + 2 + 1) * 64) >> 1));
145118781Sgibbs
145218781Sgibbs	i = ADV_MIN_ACTIVE_QNO;
145318781Sgibbs	s_addr = ADV_QADR_BEG + ADV_QBLK_SIZE;
145418781Sgibbs
145518781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD,	i + 1);
145618781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, adv->max_openings);
145718781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i);
145818781Sgibbs	i++;
145918781Sgibbs	s_addr += ADV_QBLK_SIZE;
146018781Sgibbs	for (; i < adv->max_openings; i++, s_addr += ADV_QBLK_SIZE) {
146118781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i + 1);
146218781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, i - 1);
146318781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i);
146418781Sgibbs	}
146518781Sgibbs
146618781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, ADV_QLINK_END);
146718781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, adv->max_openings - 1);
146818781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, adv->max_openings);
146918781Sgibbs	i++;
147018781Sgibbs	s_addr += ADV_QBLK_SIZE;
147118781Sgibbs
147218781Sgibbs	for (; i <= adv->max_openings + 3; i++, s_addr += ADV_QBLK_SIZE) {
147318781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i);
147418781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, i);
147518781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i);
147618781Sgibbs	}
147718781Sgibbs}
147818781Sgibbs
147918781Sgibbsstatic int
148039217Sgibbsadv_init_microcode_var(struct adv_softc *adv)
148118781Sgibbs{
148239217Sgibbs	int	 i;
148318781Sgibbs
148418781Sgibbs	for (i = 0; i <= ADV_MAX_TID; i++) {
148539217Sgibbs
148639217Sgibbs		/* Start out async all around */
148739217Sgibbs		adv_set_syncrate(adv, /*path*/NULL,
148839217Sgibbs				 i, 0, 0,
148939217Sgibbs				 ADV_TRANS_GOAL|ADV_TRANS_CUR);
149018781Sgibbs	}
149118781Sgibbs
149218781Sgibbs	adv_init_qlink_var(adv);
149318781Sgibbs
149418781Sgibbs	adv_write_lram_8(adv, ADVV_DISC_ENABLE_B, adv->disc_enable);
149518781Sgibbs	adv_write_lram_8(adv, ADVV_HOSTSCSI_ID_B, 0x01 << adv->scsi_id);
149618781Sgibbs
149739217Sgibbs	adv_write_lram_32(adv, ADVV_OVERRUN_PADDR_D, adv->overrun_physbase);
149818781Sgibbs
149939217Sgibbs	adv_write_lram_32(adv, ADVV_OVERRUN_BSIZE_D, ADV_OVERRUN_BSIZE);
150018781Sgibbs
150118781Sgibbs	ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR);
150218781Sgibbs	if (ADV_INW(adv, ADV_REG_PROG_COUNTER) != ADV_MCODE_START_ADDR) {
150339217Sgibbs		printf("adv%d: Unable to set program counter. Aborting.\n",
150418781Sgibbs		       adv->unit);
150518781Sgibbs		return (1);
150618781Sgibbs	}
150718781Sgibbs	return (0);
150818781Sgibbs}
150918781Sgibbs
151018781Sgibbsstatic void
151139217Sgibbsadv_init_qlink_var(struct adv_softc *adv)
151218781Sgibbs{
151318781Sgibbs	int	  i;
151418781Sgibbs	u_int16_t lram_addr;
151518781Sgibbs
151618781Sgibbs	adv_write_lram_8(adv, ADVV_NEXTRDY_B, 1);
151718781Sgibbs	adv_write_lram_8(adv, ADVV_DONENEXT_B, adv->max_openings);
151818781Sgibbs
151918781Sgibbs	adv_write_lram_16(adv, ADVV_FREE_Q_HEAD_W, 1);
152018781Sgibbs	adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, adv->max_openings);
152118781Sgibbs
152218781Sgibbs	adv_write_lram_8(adv, ADVV_BUSY_QHEAD_B,
152318781Sgibbs			 (u_int8_t)((int) adv->max_openings + 1));
152418781Sgibbs	adv_write_lram_8(adv, ADVV_DISC1_QHEAD_B,
152518781Sgibbs			 (u_int8_t)((int) adv->max_openings + 2));
152618781Sgibbs
152718781Sgibbs	adv_write_lram_8(adv, ADVV_TOTAL_READY_Q_B, adv->max_openings);
152818781Sgibbs
152918781Sgibbs	adv_write_lram_16(adv, ADVV_ASCDVC_ERR_CODE_W, 0);
153018781Sgibbs	adv_write_lram_16(adv, ADVV_HALTCODE_W, 0);
153118781Sgibbs	adv_write_lram_8(adv, ADVV_STOP_CODE_B, 0);
153218781Sgibbs	adv_write_lram_8(adv, ADVV_SCSIBUSY_B, 0);
153318781Sgibbs	adv_write_lram_8(adv, ADVV_WTM_FLAG_B, 0);
153439217Sgibbs	adv_write_lram_8(adv, ADVV_Q_DONE_IN_PROGRESS_B, 0);
153518781Sgibbs
153618781Sgibbs	lram_addr = ADV_QADR_BEG;
153718781Sgibbs	for (i = 0; i < 32; i++, lram_addr += 2)
153818781Sgibbs		adv_write_lram_16(adv, lram_addr, 0);
153918781Sgibbs}
154039217Sgibbs
154118781Sgibbsstatic void
154239217Sgibbsadv_disable_interrupt(struct adv_softc *adv)
154318781Sgibbs{
154418781Sgibbs	u_int16_t cfg;
154518781Sgibbs
154618781Sgibbs	cfg = ADV_INW(adv, ADV_CONFIG_LSW);
154718781Sgibbs	ADV_OUTW(adv, ADV_CONFIG_LSW, cfg & ~ADV_CFG_LSW_HOST_INT_ON);
154818781Sgibbs}
154918781Sgibbs
155018781Sgibbsstatic void
155139217Sgibbsadv_enable_interrupt(struct adv_softc *adv)
155218781Sgibbs{
155318781Sgibbs	u_int16_t cfg;
155418781Sgibbs
155518781Sgibbs	cfg = ADV_INW(adv, ADV_CONFIG_LSW);
155618781Sgibbs	ADV_OUTW(adv, ADV_CONFIG_LSW, cfg | ADV_CFG_LSW_HOST_INT_ON);
155718781Sgibbs}
155818781Sgibbs
155918781Sgibbsstatic void
156039217Sgibbsadv_toggle_irq_act(struct adv_softc *adv)
156118781Sgibbs{
156218781Sgibbs	ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_IRQ_ACT);
156318781Sgibbs	ADV_OUTW(adv, ADV_CHIP_STATUS, 0);
156418781Sgibbs}
156518781Sgibbs
156639217Sgibbsvoid
156739217Sgibbsadv_start_execution(struct adv_softc *adv)
156818781Sgibbs{
156918781Sgibbs	if (adv_read_lram_8(adv, ADV_STOP_CODE_B) != 0) {
157018781Sgibbs		adv_write_lram_8(adv, ADV_STOP_CODE_B, 0);
157118781Sgibbs	}
157218781Sgibbs}
157318781Sgibbs
157455945Sgibbsint
157539217Sgibbsadv_stop_chip(struct adv_softc *adv)
157618781Sgibbs{
157718781Sgibbs	u_int8_t cc_val;
157818781Sgibbs
157918781Sgibbs	cc_val = ADV_INB(adv, ADV_CHIP_CTRL)
158018781Sgibbs		 & (~(ADV_CC_SINGLE_STEP | ADV_CC_TEST | ADV_CC_DIAG));
158118781Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, cc_val | ADV_CC_HALT);
158218781Sgibbs	adv_set_chip_ih(adv, ADV_INS_HALT);
158318781Sgibbs	adv_set_chip_ih(adv, ADV_INS_RFLAG_WTM);
158418781Sgibbs	if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) == 0) {
158518781Sgibbs		return (0);
158618781Sgibbs	}
158718781Sgibbs	return (1);
158818781Sgibbs}
158918781Sgibbs
159039217Sgibbsstatic int
159139217Sgibbsadv_host_req_chip_halt(struct adv_softc *adv)
159239217Sgibbs{
159339217Sgibbs	int	 count;
159439217Sgibbs	u_int8_t saved_stop_code;
159539217Sgibbs
159639217Sgibbs	if (adv_is_chip_halted(adv))
159739217Sgibbs		return (1);
159839217Sgibbs
159939217Sgibbs	count = 0;
160039217Sgibbs	saved_stop_code = adv_read_lram_8(adv, ADVV_STOP_CODE_B);
160139217Sgibbs	adv_write_lram_8(adv, ADVV_STOP_CODE_B,
160239217Sgibbs			 ADV_STOP_HOST_REQ_RISC_HALT | ADV_STOP_REQ_RISC_STOP);
160339217Sgibbs	while (adv_is_chip_halted(adv) == 0
160439217Sgibbs	    && count++ < 2000)
160539217Sgibbs		;
160639217Sgibbs
160739217Sgibbs	adv_write_lram_8(adv, ADVV_STOP_CODE_B, saved_stop_code);
160839217Sgibbs	return (count < 2000);
160939217Sgibbs}
161039217Sgibbs
161118781Sgibbsstatic void
161239217Sgibbsadv_set_chip_ih(struct adv_softc *adv, u_int16_t ins_code)
161318781Sgibbs{
161418781Sgibbs	adv_set_bank(adv, 1);
161518781Sgibbs	ADV_OUTW(adv, ADV_REG_IH, ins_code);
161618781Sgibbs	adv_set_bank(adv, 0);
161718781Sgibbs}
161818781Sgibbs
161918781Sgibbs#if UNUSED
162018781Sgibbsstatic u_int8_t
162139217Sgibbsadv_get_chip_scsi_ctrl(struct adv_softc *adv)
162218781Sgibbs{
162318781Sgibbs	u_int8_t scsi_ctrl;
162418781Sgibbs
162518781Sgibbs	adv_set_bank(adv, 1);
162618781Sgibbs	scsi_ctrl = ADV_INB(adv, ADV_REG_SC);
162718781Sgibbs	adv_set_bank(adv, 0);
162818781Sgibbs	return (scsi_ctrl);
162918781Sgibbs}
163018781Sgibbs#endif
163118781Sgibbs
163218781Sgibbs/*
163318781Sgibbs * XXX Looks like more padding issues in this routine as well.
163418781Sgibbs *     There has to be a way to turn this into an insw.
163518781Sgibbs */
163618781Sgibbsstatic void
163739217Sgibbsadv_get_q_info(struct adv_softc *adv, u_int16_t s_addr,
163839217Sgibbs	       u_int16_t *inbuf, int words)
163918781Sgibbs{
164018781Sgibbs	int	i;
164118781Sgibbs
164218781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
164318781Sgibbs	for (i = 0; i < words; i++, inbuf++) {
164418781Sgibbs		if (i == 5) {
164518781Sgibbs			continue;
164618781Sgibbs		}
164718781Sgibbs		*inbuf = ADV_INW(adv, ADV_LRAM_DATA);
164818781Sgibbs	}
164918781Sgibbs}
165018781Sgibbs
165118781Sgibbsstatic u_int
165239217Sgibbsadv_get_num_free_queues(struct adv_softc *adv, u_int8_t n_qs)
165318781Sgibbs{
165418781Sgibbs	u_int	  cur_used_qs;
165518781Sgibbs	u_int	  cur_free_qs;
165618781Sgibbs
165739217Sgibbs	cur_used_qs = adv->cur_active + ADV_MIN_FREE_Q;
165818781Sgibbs
165918781Sgibbs	if ((cur_used_qs + n_qs) <= adv->max_openings) {
166018781Sgibbs		cur_free_qs = adv->max_openings - cur_used_qs;
166118781Sgibbs		return (cur_free_qs);
166218781Sgibbs	}
166339217Sgibbs	adv->openings_needed = n_qs;
166418781Sgibbs	return (0);
166518781Sgibbs}
166618781Sgibbs
166718781Sgibbsstatic u_int8_t
166839217Sgibbsadv_alloc_free_queues(struct adv_softc *adv, u_int8_t free_q_head,
166939217Sgibbs		      u_int8_t n_free_q)
167018781Sgibbs{
167118781Sgibbs	int i;
167218781Sgibbs
167318781Sgibbs	for (i = 0; i < n_free_q; i++) {
167418781Sgibbs		free_q_head = adv_alloc_free_queue(adv, free_q_head);
167518781Sgibbs		if (free_q_head == ADV_QLINK_END)
167618781Sgibbs			break;
167718781Sgibbs	}
167818781Sgibbs	return (free_q_head);
167918781Sgibbs}
168018781Sgibbs
168118781Sgibbsstatic u_int8_t
168239217Sgibbsadv_alloc_free_queue(struct adv_softc *adv, u_int8_t free_q_head)
168318781Sgibbs{
168418781Sgibbs	u_int16_t	q_addr;
168518781Sgibbs	u_int8_t	next_qp;
168618781Sgibbs	u_int8_t	q_status;
168718781Sgibbs
168818781Sgibbs	next_qp = ADV_QLINK_END;
168918781Sgibbs	q_addr = ADV_QNO_TO_QADDR(free_q_head);
169018781Sgibbs	q_status = adv_read_lram_8(adv,	q_addr + ADV_SCSIQ_B_STATUS);
169118781Sgibbs
169218781Sgibbs	if ((q_status & QS_READY) == 0)
169318781Sgibbs		next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD);
169418781Sgibbs
169518781Sgibbs	return (next_qp);
169618781Sgibbs}
169718781Sgibbs
169818781Sgibbsstatic int
169939217Sgibbsadv_send_scsi_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq,
170039217Sgibbs		    u_int8_t n_q_required)
170118781Sgibbs{
170218781Sgibbs	u_int8_t	free_q_head;
170318781Sgibbs	u_int8_t	next_qp;
170418781Sgibbs	u_int8_t	tid_no;
170518781Sgibbs	u_int8_t	target_ix;
170618781Sgibbs	int		retval;
170718781Sgibbs
170818781Sgibbs	retval = 1;
170918781Sgibbs	target_ix = scsiq->q2.target_ix;
171018781Sgibbs	tid_no = ADV_TIX_TO_TID(target_ix);
171118781Sgibbs	free_q_head = adv_read_lram_16(adv, ADVV_FREE_Q_HEAD_W) & 0xFF;
171218781Sgibbs	if ((next_qp = adv_alloc_free_queues(adv, free_q_head, n_q_required))
171318781Sgibbs	    != ADV_QLINK_END) {
171418781Sgibbs		scsiq->q1.q_no = free_q_head;
171518781Sgibbs
171618781Sgibbs		/*
171718781Sgibbs		 * Now that we know our Q number, point our sense
171839217Sgibbs		 * buffer pointer to a bus dma mapped area where
171939217Sgibbs		 * we can dma the data to.
172018781Sgibbs		 */
172139217Sgibbs		scsiq->q1.sense_addr = adv->sense_physbase
172239217Sgibbs		    + ((free_q_head - 1) * sizeof(struct scsi_sense_data));
172318781Sgibbs		adv_put_ready_sg_list_queue(adv, scsiq, free_q_head);
172418781Sgibbs		adv_write_lram_16(adv, ADVV_FREE_Q_HEAD_W, next_qp);
172518781Sgibbs		adv->cur_active += n_q_required;
172618781Sgibbs		retval = 0;
172718781Sgibbs	}
172818781Sgibbs	return (retval);
172918781Sgibbs}
173018781Sgibbs
173118781Sgibbs
173218781Sgibbsstatic void
173339217Sgibbsadv_put_ready_sg_list_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq,
173439217Sgibbs			    u_int q_no)
173518781Sgibbs{
173618781Sgibbs	u_int8_t	sg_list_dwords;
173718781Sgibbs	u_int8_t	sg_index, i;
173818781Sgibbs	u_int8_t	sg_entry_cnt;
173918781Sgibbs	u_int8_t	next_qp;
174018781Sgibbs	u_int16_t	q_addr;
174118781Sgibbs	struct		adv_sg_head *sg_head;
174218781Sgibbs	struct		adv_sg_list_q scsi_sg_q;
174318781Sgibbs
174418781Sgibbs	sg_head = scsiq->sg_head;
174518781Sgibbs
174618781Sgibbs	if (sg_head) {
174718781Sgibbs		sg_entry_cnt = sg_head->entry_cnt - 1;
174818781Sgibbs#ifdef DIAGNOSTIC
174918781Sgibbs		if (sg_entry_cnt == 0)
175039217Sgibbs			panic("adv_put_ready_sg_list_queue: ScsiQ with "
175139217Sgibbs			      "a SG list but only one element");
175218781Sgibbs		if ((scsiq->q1.cntl & QC_SG_HEAD) == 0)
175339217Sgibbs			panic("adv_put_ready_sg_list_queue: ScsiQ with "
175439217Sgibbs			      "a SG list but QC_SG_HEAD not set");
175518781Sgibbs#endif
175618781Sgibbs		q_addr = ADV_QNO_TO_QADDR(q_no);
175718781Sgibbs		sg_index = 1;
175818781Sgibbs		scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
175918781Sgibbs		scsi_sg_q.sg_head_qp = q_no;
176018781Sgibbs		scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
176118781Sgibbs		for (i = 0; i < sg_head->queue_cnt; i++) {
176218781Sgibbs			u_int8_t segs_this_q;
176318781Sgibbs
176418781Sgibbs			if (sg_entry_cnt > ADV_SG_LIST_PER_Q)
176518781Sgibbs				segs_this_q = ADV_SG_LIST_PER_Q;
176618781Sgibbs			else {
176718781Sgibbs				/* This will be the last segment then */
176818781Sgibbs				segs_this_q = sg_entry_cnt;
176918781Sgibbs				scsi_sg_q.cntl |= QCSG_SG_XFER_END;
177018781Sgibbs			}
177118781Sgibbs			scsi_sg_q.seq_no = i + 1;
177239217Sgibbs			sg_list_dwords = segs_this_q << 1;
177318781Sgibbs			if (i == 0) {
177418781Sgibbs				scsi_sg_q.sg_list_cnt = segs_this_q;
177518781Sgibbs				scsi_sg_q.sg_cur_list_cnt = segs_this_q;
177618781Sgibbs			} else {
177718781Sgibbs				scsi_sg_q.sg_list_cnt = segs_this_q - 1;
177818781Sgibbs				scsi_sg_q.sg_cur_list_cnt = segs_this_q - 1;
177918781Sgibbs			}
178018781Sgibbs			next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD);
178118781Sgibbs			scsi_sg_q.q_no = next_qp;
178218781Sgibbs			q_addr = ADV_QNO_TO_QADDR(next_qp);
178318781Sgibbs
178439217Sgibbs			adv_write_lram_16_multi(adv,
178539217Sgibbs						q_addr + ADV_SCSIQ_SGHD_CPY_BEG,
178618781Sgibbs						(u_int16_t *)&scsi_sg_q,
178718781Sgibbs						sizeof(scsi_sg_q) >> 1);
178818781Sgibbs			adv_write_lram_32_multi(adv, q_addr + ADV_SGQ_LIST_BEG,
178918781Sgibbs						(u_int32_t *)&sg_head->sg_list[sg_index],
179018781Sgibbs						sg_list_dwords);
179118781Sgibbs			sg_entry_cnt -= segs_this_q;
179218781Sgibbs			sg_index += ADV_SG_LIST_PER_Q;
179318781Sgibbs		}
179418781Sgibbs	}
179518781Sgibbs	adv_put_ready_queue(adv, scsiq, q_no);
179618781Sgibbs}
179718781Sgibbs
179818781Sgibbsstatic void
179939217Sgibbsadv_put_ready_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq,
180039217Sgibbs		    u_int q_no)
180118781Sgibbs{
180239217Sgibbs	struct		adv_target_transinfo* tinfo;
180339217Sgibbs	u_int		q_addr;
180439217Sgibbs	u_int		tid_no;
180518781Sgibbs
180639217Sgibbs	tid_no = ADV_TIX_TO_TID(scsiq->q2.target_ix);
180739217Sgibbs	tinfo = &adv->tinfo[tid_no];
180846581Sken	if ((tinfo->current.period != tinfo->goal.period)
180946581Sken	 || (tinfo->current.offset != tinfo->goal.offset)) {
181018781Sgibbs
181139217Sgibbs		adv_msgout_sdtr(adv, tinfo->goal.period, tinfo->goal.offset);
181218781Sgibbs		scsiq->q1.cntl |= QC_MSG_OUT;
181318781Sgibbs	}
181418781Sgibbs	q_addr = ADV_QNO_TO_QADDR(q_no);
181518781Sgibbs
181618781Sgibbs	scsiq->q1.status = QS_FREE;
181718781Sgibbs
181818781Sgibbs	adv_write_lram_16_multi(adv, q_addr + ADV_SCSIQ_CDB_BEG,
181918781Sgibbs				(u_int16_t *)scsiq->cdbptr,
182018781Sgibbs				scsiq->q2.cdb_len >> 1);
182118781Sgibbs
182218781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
182318781Sgibbs	adv_adj_scsiq_endian(scsiq);
182418781Sgibbs#endif
182518781Sgibbs
182618781Sgibbs	adv_put_scsiq(adv, q_addr + ADV_SCSIQ_CPY_BEG,
182718781Sgibbs		      (u_int16_t *) &scsiq->q1.cntl,
182818781Sgibbs		      ((sizeof(scsiq->q1) + sizeof(scsiq->q2)) / 2) - 1);
182918781Sgibbs
183018781Sgibbs#if CC_WRITE_IO_COUNT
183118781Sgibbs	adv_write_lram_16(adv, q_addr + ADV_SCSIQ_W_REQ_COUNT,
183218781Sgibbs			  adv->req_count);
183318781Sgibbs#endif
183418781Sgibbs
183518781Sgibbs#if CC_CLEAR_DMA_REMAIN
183618781Sgibbs
183718781Sgibbs	adv_write_lram_32(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_ADDR, 0);
183818781Sgibbs	adv_write_lram_32(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_CNT, 0);
183918781Sgibbs#endif
184018781Sgibbs
184118781Sgibbs	adv_write_lram_16(adv, q_addr + ADV_SCSIQ_B_STATUS,
184218781Sgibbs			  (scsiq->q1.q_no << 8) | QS_READY);
184318781Sgibbs}
184418781Sgibbs
184518781Sgibbsstatic void
184639217Sgibbsadv_put_scsiq(struct adv_softc *adv, u_int16_t s_addr,
184739217Sgibbs	      u_int16_t *buffer, int words)
184818781Sgibbs{
184918781Sgibbs	int	i;
185018781Sgibbs
185118781Sgibbs	/*
185218781Sgibbs	 * XXX This routine makes *gross* assumptions
185318781Sgibbs	 * about padding in the data structures.
185418781Sgibbs	 * Either the data structures should have explicit
185518781Sgibbs	 * padding members added, or they should have padding
185618781Sgibbs	 * turned off via compiler attributes depending on
185718781Sgibbs	 * which yields better overall performance.  My hunch
185818781Sgibbs	 * would be that turning off padding would be the
185918781Sgibbs	 * faster approach as an outsw is much faster than
186018781Sgibbs	 * this crude loop and accessing un-aligned data
186118781Sgibbs	 * members isn't *that* expensive.  The other choice
186218781Sgibbs	 * would be to modify the ASC script so that the
186318781Sgibbs	 * the adv_scsiq_1 structure can be re-arranged so
186418781Sgibbs	 * padding isn't required.
186518781Sgibbs	 */
186618781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
186718781Sgibbs	for (i = 0; i < words; i++, buffer++) {
186818781Sgibbs		if (i == 2 || i == 10) {
186918781Sgibbs			continue;
187018781Sgibbs		}
187118781Sgibbs		ADV_OUTW(adv, ADV_LRAM_DATA, *buffer);
187218781Sgibbs	}
187318781Sgibbs}
187418781Sgibbs
1875111342Sobrien#if BYTE_ORDER == BIG_ENDIAN
1876111342Sobrienvoid
1877111342Sobrienadv_adj_endian_qdone_info(struct adv_q_done_info *scsiq)
1878111342Sobrien{
1879111342Sobrien
1880111342Sobrien	panic("adv(4) not supported on big-endian machines.\n");
1881111342Sobrien}
1882111342Sobrien
1883111342Sobrienvoid
1884111342Sobrienadv_adj_scsiq_endian(struct adv_scsi_q *scsiq)
1885111342Sobrien{
1886111342Sobrien
1887111342Sobrien	panic("adv(4) not supported on big-endian machines.\n");
1888111342Sobrien}
1889111342Sobrien#endif
1890111342Sobrien
189139217Sgibbsstatic void
189239217Sgibbsadv_handle_extmsg_in(struct adv_softc *adv, u_int16_t halt_q_addr,
189339217Sgibbs		     u_int8_t q_cntl, target_bit_vector target_mask,
189439217Sgibbs		     int tid_no)
189518781Sgibbs{
189639217Sgibbs	struct	ext_msg ext_msg;
189718781Sgibbs
189839217Sgibbs	adv_read_lram_16_multi(adv, ADVV_MSGIN_BEG, (u_int16_t *) &ext_msg,
189939217Sgibbs			       sizeof(ext_msg) >> 1);
190039217Sgibbs	if ((ext_msg.msg_type == MSG_EXTENDED)
190139217Sgibbs	 && (ext_msg.msg_req == MSG_EXT_SDTR)
190239217Sgibbs	 && (ext_msg.msg_len == MSG_EXT_SDTR_LEN)) {
190355945Sgibbs		union	  ccb *ccb;
190455945Sgibbs		struct	  adv_target_transinfo* tinfo;
190555945Sgibbs		u_int32_t cinfo_index;
190639217Sgibbs		u_int	 period;
190739217Sgibbs		u_int	 offset;
190839217Sgibbs		int	 sdtr_accept;
190939217Sgibbs		u_int8_t orig_offset;
191039217Sgibbs
191155945Sgibbs		cinfo_index =
191255945Sgibbs		    adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX);
191355945Sgibbs		ccb = adv->ccb_infos[cinfo_index].ccb;
191439217Sgibbs		tinfo = &adv->tinfo[tid_no];
191539217Sgibbs		sdtr_accept = TRUE;
191639217Sgibbs
191739217Sgibbs		orig_offset = ext_msg.req_ack_offset;
191839217Sgibbs		if (ext_msg.xfer_period < tinfo->goal.period) {
191939217Sgibbs                	sdtr_accept = FALSE;
192039217Sgibbs			ext_msg.xfer_period = tinfo->goal.period;
192139217Sgibbs		}
192239217Sgibbs
192339217Sgibbs		/* Perform range checking */
192439217Sgibbs		period = ext_msg.xfer_period;
192539217Sgibbs		offset = ext_msg.req_ack_offset;
192639217Sgibbs		adv_period_offset_to_sdtr(adv, &period,  &offset, tid_no);
192739217Sgibbs		ext_msg.xfer_period = period;
192839217Sgibbs		ext_msg.req_ack_offset = offset;
192939217Sgibbs
193039217Sgibbs		/* Record our current sync settings */
193139217Sgibbs		adv_set_syncrate(adv, ccb->ccb_h.path,
193239217Sgibbs				 tid_no, ext_msg.xfer_period,
193339217Sgibbs				 ext_msg.req_ack_offset,
193439217Sgibbs				 ADV_TRANS_GOAL|ADV_TRANS_ACTIVE);
193539217Sgibbs
193639217Sgibbs		/* Offset too high or large period forced async */
193739217Sgibbs		if (orig_offset != ext_msg.req_ack_offset)
193839217Sgibbs			sdtr_accept = FALSE;
193939217Sgibbs
194039217Sgibbs		if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
194139217Sgibbs			/* Valid response to our requested negotiation */
194239217Sgibbs			q_cntl &= ~QC_MSG_OUT;
194339217Sgibbs		} else {
194439217Sgibbs			/* Must Respond */
194539217Sgibbs			q_cntl |= QC_MSG_OUT;
194639217Sgibbs			adv_msgout_sdtr(adv, ext_msg.xfer_period,
194739217Sgibbs					ext_msg.req_ack_offset);
194839217Sgibbs		}
194939217Sgibbs
195039217Sgibbs	} else if (ext_msg.msg_type == MSG_EXTENDED
195139217Sgibbs		&& ext_msg.msg_req == MSG_EXT_WDTR
195239217Sgibbs		&& ext_msg.msg_len == MSG_EXT_WDTR_LEN) {
195339217Sgibbs
195439217Sgibbs		ext_msg.wdtr_width = 0;
195539217Sgibbs		adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG,
195639217Sgibbs					(u_int16_t *)&ext_msg,
195739217Sgibbs					sizeof(ext_msg) >> 1);
195839217Sgibbs		q_cntl |= QC_MSG_OUT;
195939217Sgibbs        } else {
196039217Sgibbs
196139217Sgibbs		ext_msg.msg_type = MSG_MESSAGE_REJECT;
196239217Sgibbs		adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG,
196339217Sgibbs					(u_int16_t *)&ext_msg,
196439217Sgibbs					sizeof(ext_msg) >> 1);
196539217Sgibbs		q_cntl |= QC_MSG_OUT;
196639217Sgibbs        }
196739217Sgibbs	adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl);
196839217Sgibbs}
196939217Sgibbs
197039217Sgibbsstatic void
197139217Sgibbsadv_msgout_sdtr(struct adv_softc *adv, u_int8_t sdtr_period,
197239217Sgibbs		u_int8_t sdtr_offset)
197339217Sgibbs{
197439217Sgibbs	struct	 ext_msg sdtr_buf;
197539217Sgibbs
197618781Sgibbs	sdtr_buf.msg_type = MSG_EXTENDED;
197718781Sgibbs	sdtr_buf.msg_len = MSG_EXT_SDTR_LEN;
197818781Sgibbs	sdtr_buf.msg_req = MSG_EXT_SDTR;
197918781Sgibbs	sdtr_buf.xfer_period = sdtr_period;
198018781Sgibbs	sdtr_offset &= ADV_SYN_MAX_OFFSET;
198118781Sgibbs	sdtr_buf.req_ack_offset = sdtr_offset;
198218781Sgibbs	adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG,
198318781Sgibbs				(u_int16_t *) &sdtr_buf,
198418781Sgibbs				sizeof(sdtr_buf) / 2);
198518781Sgibbs}
198618781Sgibbs
198739217Sgibbsint
198839217Sgibbsadv_abort_ccb(struct adv_softc *adv, int target, int lun, union ccb *ccb,
198939217Sgibbs	      u_int32_t status, int queued_only)
199018781Sgibbs{
199139217Sgibbs	u_int16_t q_addr;
199239217Sgibbs	u_int8_t  q_no;
199339217Sgibbs	struct adv_q_done_info scsiq_buf;
199439217Sgibbs	struct adv_q_done_info *scsiq;
199539217Sgibbs	u_int8_t  target_ix;
199639217Sgibbs	int	  count;
199718781Sgibbs
199839217Sgibbs	scsiq = &scsiq_buf;
199939217Sgibbs	target_ix = ADV_TIDLUN_TO_IX(target, lun);
200039217Sgibbs	count = 0;
200139217Sgibbs	for (q_no = ADV_MIN_ACTIVE_QNO; q_no <= adv->max_openings; q_no++) {
200255945Sgibbs		struct adv_ccb_info *ccb_info;
200339217Sgibbs		q_addr = ADV_QNO_TO_QADDR(q_no);
200439217Sgibbs
200539217Sgibbs		adv_copy_lram_doneq(adv, q_addr, scsiq, adv->max_dma_count);
200655945Sgibbs		ccb_info = &adv->ccb_infos[scsiq->d2.ccb_index];
200739217Sgibbs		if (((scsiq->q_status & QS_READY) != 0)
200839217Sgibbs		 && ((scsiq->q_status & QS_ABORTED) == 0)
200939217Sgibbs		 && ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)
201039217Sgibbs		 && (scsiq->d2.target_ix == target_ix)
201139217Sgibbs		 && (queued_only == 0
201239217Sgibbs		  || !(scsiq->q_status & (QS_DISC1|QS_DISC2|QS_BUSY|QS_DONE)))
201355945Sgibbs		 && (ccb == NULL || (ccb == ccb_info->ccb))) {
201439217Sgibbs			union ccb *aborted_ccb;
201539217Sgibbs			struct adv_ccb_info *cinfo;
201639217Sgibbs
201739217Sgibbs			scsiq->q_status |= QS_ABORTED;
201839217Sgibbs			adv_write_lram_8(adv, q_addr + ADV_SCSIQ_B_STATUS,
201939217Sgibbs					 scsiq->q_status);
202055945Sgibbs			aborted_ccb = ccb_info->ccb;
202139217Sgibbs			/* Don't clobber earlier error codes */
202239217Sgibbs			if ((aborted_ccb->ccb_h.status & CAM_STATUS_MASK)
202339217Sgibbs			  == CAM_REQ_INPROG)
202439217Sgibbs				aborted_ccb->ccb_h.status |= status;
202539217Sgibbs			cinfo = (struct adv_ccb_info *)
202639217Sgibbs			    aborted_ccb->ccb_h.ccb_cinfo_ptr;
202739217Sgibbs			cinfo->state |= ACCB_ABORT_QUEUED;
202839217Sgibbs			count++;
202918781Sgibbs		}
203018781Sgibbs	}
203139217Sgibbs	return (count);
203218781Sgibbs}
203318781Sgibbs
203439217Sgibbsint
203555945Sgibbsadv_reset_bus(struct adv_softc *adv, int initiate_bus_reset)
203639217Sgibbs{
203739217Sgibbs	int count;
203839217Sgibbs	int i;
203939217Sgibbs	union ccb *ccb;
204039217Sgibbs
204155945Sgibbs	i = 200;
204255945Sgibbs	while ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_SCSI_RESET_ACTIVE) != 0
204355945Sgibbs	    && i--)
204455945Sgibbs		DELAY(1000);
204555945Sgibbs	adv_reset_chip(adv, initiate_bus_reset);
204639217Sgibbs	adv_reinit_lram(adv);
204755945Sgibbs	for (i = 0; i <= ADV_MAX_TID; i++)
204855945Sgibbs		adv_set_syncrate(adv, NULL, i, /*period*/0,
204955945Sgibbs				 /*offset*/0, ADV_TRANS_CUR);
205039217Sgibbs	ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR);
205139217Sgibbs
205239217Sgibbs	/* Tell the XPT layer that a bus reset occured */
205339217Sgibbs	if (adv->path != NULL)
205439217Sgibbs		xpt_async(AC_BUS_RESET, adv->path, NULL);
205539217Sgibbs
205639217Sgibbs	count = 0;
205739217Sgibbs	while ((ccb = (union ccb *)LIST_FIRST(&adv->pending_ccbs)) != NULL) {
205839217Sgibbs		if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG)
205939217Sgibbs			ccb->ccb_h.status |= CAM_SCSI_BUS_RESET;
206039217Sgibbs		adv_done(adv, ccb, QD_ABORTED_BY_HOST, 0, 0, 0);
206139217Sgibbs		count++;
206239217Sgibbs	}
206339217Sgibbs
206439217Sgibbs	adv_start_chip(adv);
206539217Sgibbs	return (count);
206639217Sgibbs}
206739217Sgibbs
206818781Sgibbsstatic void
206939217Sgibbsadv_set_sdtr_reg_at_id(struct adv_softc *adv, int tid, u_int8_t sdtr_data)
207018781Sgibbs{
207139217Sgibbs	int orig_id;
207239217Sgibbs
207339217Sgibbs    	adv_set_bank(adv, 1);
207439217Sgibbs    	orig_id = ffs(ADV_INB(adv, ADV_HOST_SCSIID)) - 1;
207539217Sgibbs    	ADV_OUTB(adv, ADV_HOST_SCSIID, tid);
207639217Sgibbs	if (ADV_INB(adv, ADV_HOST_SCSIID) == (0x01 << tid)) {
207739217Sgibbs		adv_set_bank(adv, 0);
207839217Sgibbs		ADV_OUTB(adv, ADV_SYN_OFFSET, sdtr_data);
207939217Sgibbs	}
208039217Sgibbs    	adv_set_bank(adv, 1);
208139217Sgibbs    	ADV_OUTB(adv, ADV_HOST_SCSIID, orig_id);
208239217Sgibbs	adv_set_bank(adv, 0);
208318781Sgibbs}
2084