advlib.c revision 19426
118781Sgibbs/*
218781Sgibbs * Low level routines for the Advanced Systems Inc. SCSI controllers chips
318781Sgibbs *
418781Sgibbs * Copyright (c) 1996 Justin T. 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
1118781Sgibbs *    notice immediately at the beginning of the file, without modification,
1218781Sgibbs *    this list of conditions, and the following disclaimer.
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 *
3119426Sgibbs *      $Id: advlib.c,v 1.1.1.1 1996/10/07 02:07:06 gibbs Exp $
3218781Sgibbs */
3318781Sgibbs/*
3418781Sgibbs * Ported from:
3518781Sgibbs * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
3618781Sgibbs *
3718781Sgibbs * Copyright (c) 1995-1996 Advanced System Products, Inc.
3818781Sgibbs * All Rights Reserved.
3918781Sgibbs *
4018781Sgibbs * Redistribution and use in source and binary forms, with or without
4118781Sgibbs * modification, are permitted provided that redistributions of source
4218781Sgibbs * code retain the above copyright notice and this comment without
4318781Sgibbs * modification.
4418781Sgibbs */
4518781Sgibbs
4618781Sgibbs#include <sys/param.h>
4718781Sgibbs#include <sys/systm.h>
4818781Sgibbs
4918781Sgibbs#include <machine/clock.h>
5018781Sgibbs
5118781Sgibbs#include <scsi/scsi_all.h>
5218781Sgibbs#include <scsi/scsi_message.h>
5318781Sgibbs#include <scsi/scsi_disk.h>
5418781Sgibbs
5518781Sgibbs#include <vm/vm.h>
5618781Sgibbs#include <vm/vm_param.h>
5718781Sgibbs#include <vm/pmap.h>
5818781Sgibbs
5918781Sgibbs#include <dev/advansys/advlib.h>
6018781Sgibbs#include <dev/advansys/advmcode.h>
6118781Sgibbs
6218781Sgibbs/*
6318781Sgibbs * Allowable periods in ns
6418781Sgibbs */
6518781Sgibbsu_int8_t adv_sdtr_period_tbl[] =
6618781Sgibbs{
6718781Sgibbs	25,
6818781Sgibbs	30,
6918781Sgibbs	35,
7018781Sgibbs	40,
7118781Sgibbs	50,
7218781Sgibbs	60,
7318781Sgibbs	70,
7418781Sgibbs	85
7518781Sgibbs};
7618781Sgibbs
7718781Sgibbsstruct sdtr_xmsg {
7818781Sgibbs	u_int8_t	msg_type;
7918781Sgibbs	u_int8_t	msg_len;
8018781Sgibbs	u_int8_t	msg_req;
8118781Sgibbs	u_int8_t	xfer_period;
8218781Sgibbs	u_int8_t	req_ack_offset;
8318781Sgibbs	u_int8_t	res;
8418781Sgibbs};
8518781Sgibbs
8618781Sgibbs/*
8718781Sgibbs * Some of the early PCI adapters have problems with
8818781Sgibbs * async transfers.  Instead try to use an offset of
8918781Sgibbs * 1.
9018781Sgibbs */
9118781Sgibbs#define ASYN_SDTR_DATA_FIX 0x41
9218781Sgibbs
9318781Sgibbs/* LRAM routines */
9418781Sgibbsstatic void	 adv_read_lram_16_multi __P((struct adv_softc *adv, u_int16_t s_addr,
9518781Sgibbs					     u_int16_t *buffer, int count));
9618781Sgibbsstatic void	 adv_write_lram_16_multi __P((struct adv_softc *adv,
9718781Sgibbs					      u_int16_t s_addr, u_int16_t *buffer,
9818781Sgibbs					      int count));
9918781Sgibbsstatic void	 adv_mset_lram_16 __P((struct adv_softc *adv,
10018781Sgibbs					u_int16_t s_addr, u_int16_t set_value,
10118781Sgibbs				       int count));
10218781Sgibbsstatic u_int32_t adv_msum_lram_16 __P((struct adv_softc *adv, u_int16_t s_addr, int count));
10318781Sgibbs
10418781Sgibbsstatic int	 adv_write_and_verify_lram_16 __P((struct adv_softc *adv,
10518781Sgibbs						   u_int16_t addr, u_int16_t value));
10618781Sgibbsstatic u_int32_t adv_read_lram_32 __P((struct adv_softc *adv, u_int16_t addr));
10718781Sgibbs
10818781Sgibbs
10918781Sgibbsstatic void	 adv_write_lram_32 __P((struct adv_softc *adv, u_int16_t addr,
11018781Sgibbs					u_int32_t value));
11118781Sgibbsstatic void	 adv_write_lram_32_multi __P((struct adv_softc *adv, u_int16_t s_addr,
11218781Sgibbs					      u_int32_t *buffer, int count));
11318781Sgibbs
11418781Sgibbs/* EEPROM routines */
11518781Sgibbsstatic u_int16_t adv_read_eeprom_16 __P((struct adv_softc *adv, u_int8_t addr));
11618781Sgibbsstatic u_int16_t adv_write_eeprom_16 __P((struct adv_softc *adv, u_int8_t addr, u_int16_t value));
11718781Sgibbsstatic int	 adv_write_eeprom_cmd_reg __P((struct adv_softc *adv, 	u_int8_t cmd_reg));
11818781Sgibbsstatic int	 adv_set_eeprom_config_once __P((struct adv_softc *adv,
11918781Sgibbs						 struct adv_eeprom_config *eeprom_config));
12018781Sgibbs
12118781Sgibbs/* Initialization */
12219426Sgibbsstatic u_int32_t adv_load_microcode __P((struct adv_softc *adv,
12319426Sgibbs					 u_int16_t s_addr, u_int16_t *mcode_buf,					 u_int16_t mcode_size));
12418781Sgibbsstatic void	 adv_init_lram __P((struct adv_softc *adv));
12518781Sgibbsstatic int	 adv_init_microcode_var __P((struct adv_softc *adv));
12618781Sgibbsstatic void	 adv_init_qlink_var __P((struct adv_softc *adv));
12718781Sgibbs
12818781Sgibbs/* Interrupts */
12918781Sgibbsstatic void	 adv_disable_interrupt __P((struct adv_softc *adv));
13018781Sgibbsstatic void	 adv_enable_interrupt __P((struct adv_softc *adv));
13118781Sgibbsstatic void	 adv_toggle_irq_act __P((struct adv_softc *adv));
13218781Sgibbs
13318781Sgibbs/* Chip Control */
13418781Sgibbs#if UNUSED
13518781Sgibbsstatic void	 adv_start_execution __P((struct adv_softc *adv));
13618781Sgibbs#endif
13718781Sgibbsstatic int	 adv_start_chip __P((struct adv_softc *adv));
13818781Sgibbsstatic int	 adv_stop_chip __P((struct adv_softc *adv));
13919426Sgibbsstatic void	 adv_set_chip_ih __P((struct adv_softc *adv,
14019426Sgibbs				      u_int16_t ins_code));
14118781Sgibbsstatic void	 adv_set_bank __P((struct adv_softc *adv, u_int8_t bank));
14218781Sgibbs#if UNUSED
14318781Sgibbsstatic u_int8_t  adv_get_chip_scsi_ctrl __P((struct adv_softc *adv));
14418781Sgibbs#endif
14518781Sgibbs
14618781Sgibbs/* Queue handling and execution */
14718781Sgibbsstatic int	 adv_sgcount_to_qcount __P((int sgcount));
14818781Sgibbsstatic void	 adv_get_q_info __P((struct adv_softc *adv, u_int16_t s_addr, 	u_int16_t *inbuf,
14918781Sgibbs				     int words));
15019426Sgibbsstatic u_int	 adv_get_num_free_queues __P((struct adv_softc *adv,
15119426Sgibbs					      u_int8_t n_qs));
15219426Sgibbsstatic u_int8_t  adv_alloc_free_queues __P((struct adv_softc *adv,
15319426Sgibbs					    u_int8_t free_q_head,
15418781Sgibbs					    u_int8_t n_free_q));
15519426Sgibbsstatic u_int8_t  adv_alloc_free_queue __P((struct adv_softc *adv,
15619426Sgibbs					   u_int8_t free_q_head));
15719426Sgibbsstatic int	 adv_send_scsi_queue __P((struct adv_softc *adv,
15819426Sgibbs					  struct adv_scsi_q *scsiq,
15918781Sgibbs					  u_int8_t n_q_required));
16019426Sgibbsstatic void	 adv_put_ready_sg_list_queue __P((struct adv_softc *adv,
16119426Sgibbs						  struct adv_scsi_q *scsiq,
16218781Sgibbs						  u_int8_t q_no));
16319426Sgibbsstatic void	 adv_put_ready_queue __P((struct adv_softc *adv,
16419426Sgibbs					  struct adv_scsi_q *scsiq,
16519426Sgibbs					  u_int8_t q_no));
16619426Sgibbsstatic void	 adv_put_scsiq __P((struct adv_softc *adv, u_int16_t s_addr,
16719426Sgibbs				    u_int16_t *buffer, int words));
16818781Sgibbs
16918781Sgibbs/* SDTR */
17019426Sgibbsstatic u_int8_t  adv_msgout_sdtr __P((struct adv_softc *adv,
17119426Sgibbs				      u_int8_t sdtr_period,
17219426Sgibbs				      u_int8_t sdtr_offset));
17319426Sgibbsstatic u_int8_t  adv_get_card_sync_setting __P((u_int8_t period,
17419426Sgibbs						u_int8_t offset));
17519426Sgibbsstatic void	 adv_set_chip_sdtr __P((struct adv_softc *adv,
17619426Sgibbs					u_int8_t sdtr_data,
17718781Sgibbs					u_int8_t tid_no));
17818781Sgibbs
17918781Sgibbs
18019426Sgibbs/* Exported functions first */
18118781Sgibbs
18218781Sgibbsu_int8_t
18318781Sgibbsadv_read_lram_8(adv, addr)
18418781Sgibbs	struct adv_softc *adv;
18518781Sgibbs	u_int16_t addr;
18618781Sgibbs
18718781Sgibbs{
18818781Sgibbs	u_int8_t   byte_data;
18918781Sgibbs	u_int16_t  word_data;
19018781Sgibbs
19118781Sgibbs	/*
19218781Sgibbs	 * LRAM is accessed on 16bit boundaries.
19318781Sgibbs	 */
19418781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr & 0xFFFE);
19518781Sgibbs	word_data = ADV_INW(adv, ADV_LRAM_DATA);
19618781Sgibbs	if (addr & 1) {
19718781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
19818781Sgibbs		byte_data = (u_int8_t)(word_data & 0xFF);
19918781Sgibbs#else
20018781Sgibbs		byte_data = (u_int8_t)((word_data >> 8) & 0xFF);
20118781Sgibbs#endif
20218781Sgibbs	} else {
20318781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
20418781Sgibbs		byte_data = (u_int8_t)((word_data >> 8) & 0xFF);
20518781Sgibbs#else
20618781Sgibbs		byte_data = (u_int8_t)(word_data & 0xFF);
20718781Sgibbs#endif
20818781Sgibbs	}
20918781Sgibbs	return (byte_data);
21018781Sgibbs}
21118781Sgibbs
21218781Sgibbsvoid
21318781Sgibbsadv_write_lram_8(adv, addr, value)
21418781Sgibbs	struct adv_softc *adv;
21518781Sgibbs	u_int16_t addr;
21618781Sgibbs	u_int8_t value;
21718781Sgibbs{
21818781Sgibbs	u_int16_t word_data;
21918781Sgibbs
22018781Sgibbs	word_data = adv_read_lram_16(adv, addr & 0xFFFE);
22118781Sgibbs	if (addr & 1) {
22218781Sgibbs		word_data &= 0x00FF;
22318781Sgibbs		word_data |= (((u_int8_t)value << 8) & 0xFF00);
22418781Sgibbs	} else {
22518781Sgibbs		word_data &= 0xFF00;
22618781Sgibbs		word_data |= ((u_int8_t)value & 0x00FF);
22718781Sgibbs	}
22818781Sgibbs	adv_write_lram_16(adv, addr & 0xFFFE, word_data);
22918781Sgibbs}
23018781Sgibbs
23118781Sgibbs
23218781Sgibbsu_int16_t
23318781Sgibbsadv_read_lram_16(adv, addr)
23418781Sgibbs	struct adv_softc *adv;
23518781Sgibbs	u_int16_t addr;
23618781Sgibbs{
23718781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
23818781Sgibbs	return (ADV_INW(adv, ADV_LRAM_DATA));
23918781Sgibbs}
24018781Sgibbs
24118781Sgibbsvoid
24218781Sgibbsadv_write_lram_16(adv, addr, value)
24318781Sgibbs	struct adv_softc *adv;
24418781Sgibbs	u_int16_t addr;
24518781Sgibbs	u_int16_t value;
24618781Sgibbs{
24718781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
24818781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, value);
24918781Sgibbs}
25018781Sgibbs
25118781Sgibbs
25218781Sgibbs/*
25318781Sgibbs * Return the fully qualified board type for the adapter.
25418781Sgibbs * The chip_revision must be set before this function is called.
25518781Sgibbs */
25618781Sgibbsvoid
25718781Sgibbsadv_get_board_type(adv)
25818781Sgibbs	struct adv_softc *adv;
25918781Sgibbs{
26018781Sgibbs	if ((adv->chip_version >= ADV_CHIP_MIN_VER_VL) &&
26118781Sgibbs	    (adv->chip_version <= ADV_CHIP_MAX_VER_VL)) {
26218781Sgibbs		if (((adv->iobase & 0x0C30) == 0x0C30) ||
26318781Sgibbs			((adv->iobase & 0x0C50) == 0x0C50)) {
26418781Sgibbs			adv->type = ADV_EISA;
26518781Sgibbs		} else
26618781Sgibbs			adv->type = ADV_VL;
26718781Sgibbs	} else if ((adv->chip_version >= ADV_CHIP_MIN_VER_ISA) &&
26818781Sgibbs		   (adv->chip_version <= ADV_CHIP_MAX_VER_ISA)) {
26918781Sgibbs		if (adv->chip_version >= ADV_CHIP_MIN_VER_ISA_PNP) {
27018781Sgibbs			adv->type = ADV_ISAPNP;
27118781Sgibbs		} else
27218781Sgibbs			adv->type = ADV_ISA;
27318781Sgibbs	} else if ((adv->chip_version >= ADV_CHIP_MIN_VER_PCI) &&
27418781Sgibbs		   (adv->chip_version <= ADV_CHIP_MAX_VER_PCI)) {
27518781Sgibbs		adv->type = ADV_PCI;
27618781Sgibbs	} else
27718781Sgibbs		panic("adv_get_board_type: Unknown board type encountered");
27818781Sgibbs}
27918781Sgibbs
28018781Sgibbsu_int16_t
28118781Sgibbsadv_get_eeprom_config(adv, eeprom_config)
28218781Sgibbs	struct adv_softc *adv;
28318781Sgibbs	struct	  adv_eeprom_config  *eeprom_config;
28418781Sgibbs{
28518781Sgibbs	u_int16_t	sum;
28618781Sgibbs	u_int16_t	*wbuf;
28718781Sgibbs	u_int8_t	cfg_beg;
28818781Sgibbs	u_int8_t	cfg_end;
28918781Sgibbs	u_int8_t	s_addr;
29018781Sgibbs
29118781Sgibbs	wbuf = (u_int16_t *)eeprom_config;
29218781Sgibbs	sum = 0;
29318781Sgibbs
29418781Sgibbs	for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
29518781Sgibbs		*wbuf = adv_read_eeprom_16(adv, s_addr);
29618781Sgibbs		sum += *wbuf;
29718781Sgibbs	}
29818781Sgibbs
29918781Sgibbs	if (adv->type & ADV_VL) {
30018781Sgibbs		cfg_beg = ADV_EEPROM_CFG_BEG_VL;
30118781Sgibbs		cfg_end = ADV_EEPROM_MAX_ADDR_VL;
30218781Sgibbs	} else {
30318781Sgibbs		cfg_beg = ADV_EEPROM_CFG_BEG;
30418781Sgibbs		cfg_end = ADV_EEPROM_MAX_ADDR;
30518781Sgibbs	}
30618781Sgibbs
30718781Sgibbs	for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
30818781Sgibbs		*wbuf = adv_read_eeprom_16(adv, s_addr);
30918781Sgibbs		sum += *wbuf;
31018781Sgibbs#if ADV_DEBUG_EEPROM
31118781Sgibbs		printf("Addr 0x%x: 0x%04x\n", s_addr, *wbuf);
31218781Sgibbs#endif
31318781Sgibbs	}
31418781Sgibbs	*wbuf = adv_read_eeprom_16(adv, s_addr);
31518781Sgibbs	return (sum);
31618781Sgibbs}
31718781Sgibbs
31818781Sgibbsint
31918781Sgibbsadv_set_eeprom_config(adv, eeprom_config)
32018781Sgibbs	struct adv_softc *adv;
32118781Sgibbs	struct adv_eeprom_config *eeprom_config;
32218781Sgibbs{
32318781Sgibbs	int	retry;
32418781Sgibbs
32518781Sgibbs	retry = 0;
32618781Sgibbs	while (1) {
32718781Sgibbs		if (adv_set_eeprom_config_once(adv, eeprom_config) == 0) {
32818781Sgibbs			break;
32918781Sgibbs		}
33018781Sgibbs		if (++retry > ADV_EEPROM_MAX_RETRY) {
33118781Sgibbs			break;
33218781Sgibbs		}
33318781Sgibbs	}
33418781Sgibbs	return (retry > ADV_EEPROM_MAX_RETRY);
33518781Sgibbs}
33618781Sgibbs
33718781Sgibbsint
33818781Sgibbsadv_reset_chip_and_scsi_bus(adv)
33918781Sgibbs	struct adv_softc *adv;
34018781Sgibbs{
34118781Sgibbs	adv_stop_chip(adv);
34218781Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_CHIP_RESET | ADV_CC_SCSI_RESET | ADV_CC_HALT);
34318781Sgibbs	DELAY(200 * 1000);
34418781Sgibbs
34518781Sgibbs	adv_set_chip_ih(adv, ADV_INS_RFLAG_WTM);
34618781Sgibbs	adv_set_chip_ih(adv, ADV_INS_HALT);
34718781Sgibbs
34818781Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_CHIP_RESET | ADV_CC_HALT);
34918781Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT);
35018781Sgibbs	DELAY(200 * 1000);
35118781Sgibbs	return (adv_is_chip_halted(adv));
35218781Sgibbs}
35318781Sgibbs
35418781Sgibbsint
35518781Sgibbsadv_test_external_lram(adv)
35618781Sgibbs	struct adv_softc* adv;
35718781Sgibbs{
35818781Sgibbs	u_int16_t	q_addr;
35918781Sgibbs	u_int16_t	saved_value;
36018781Sgibbs	int		success;
36118781Sgibbs
36218781Sgibbs	success = 0;
36318781Sgibbs
36418781Sgibbs	/* XXX Why 241? */
36518781Sgibbs	q_addr = ADV_QNO_TO_QADDR(241);
36618781Sgibbs	saved_value = adv_read_lram_16(adv, q_addr);
36718781Sgibbs	if (adv_write_and_verify_lram_16(adv, q_addr, 0x55AA) == 0) {
36818781Sgibbs		success = 1;
36918781Sgibbs		adv_write_lram_16(adv, q_addr, saved_value);
37018781Sgibbs	}
37118781Sgibbs	return (success);
37218781Sgibbs}
37318781Sgibbs
37418781Sgibbs
37518781Sgibbsint
37618781Sgibbsadv_init_lram_and_mcode(adv)
37718781Sgibbs	struct adv_softc *adv;
37818781Sgibbs{
37918781Sgibbs	u_int32_t	retval;
38018781Sgibbs	adv_disable_interrupt(adv);
38118781Sgibbs
38218781Sgibbs	adv_init_lram(adv);
38318781Sgibbs
38418781Sgibbs	retval = adv_load_microcode(adv, 0, (u_int16_t *)adv_mcode, adv_mcode_size);
38518781Sgibbs	if (retval != adv_mcode_chksum) {
38618781Sgibbs		printf("adv%d: Microcode download failed checksum!\n",
38718781Sgibbs		       adv->unit);
38818781Sgibbs		return (1);
38918781Sgibbs	}
39018781Sgibbs
39118781Sgibbs	if (adv_init_microcode_var(adv) != 0)
39218781Sgibbs		return (1);
39318781Sgibbs
39418781Sgibbs	adv_enable_interrupt(adv);
39518781Sgibbs	return (0);
39618781Sgibbs}
39718781Sgibbs
39818781Sgibbsu_int8_t
39918781Sgibbsadv_get_chip_irq(adv)
40018781Sgibbs	struct adv_softc *adv;
40118781Sgibbs{
40218781Sgibbs	u_int16_t	cfg_lsw;
40318781Sgibbs	u_int8_t	chip_irq;
40418781Sgibbs
40518781Sgibbs	cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW);
40618781Sgibbs
40718781Sgibbs	if ((adv->type & ADV_VL) != 0) {
40818781Sgibbs		chip_irq = (u_int8_t)(((cfg_lsw >> 2) & 0x07));
40918781Sgibbs		if ((chip_irq == 0) ||
41018781Sgibbs		    (chip_irq == 4) ||
41118781Sgibbs		    (chip_irq == 7)) {
41218781Sgibbs			return (0);
41318781Sgibbs		}
41418781Sgibbs		return (chip_irq + (ADV_MIN_IRQ_NO - 1));
41518781Sgibbs	}
41618781Sgibbs	chip_irq = (u_int8_t)(((cfg_lsw >> 2) & 0x03));
41718781Sgibbs	if (chip_irq == 3)
41818781Sgibbs		chip_irq += 2;
41918781Sgibbs	return (chip_irq + ADV_MIN_IRQ_NO);
42018781Sgibbs}
42118781Sgibbs
42218781Sgibbsu_int8_t
42318781Sgibbsadv_set_chip_irq(adv, irq_no)
42418781Sgibbs	struct adv_softc *adv;
42518781Sgibbs	u_int8_t irq_no;
42618781Sgibbs{
42718781Sgibbs	u_int16_t	cfg_lsw;
42818781Sgibbs
42918781Sgibbs	if ((adv->type & ADV_VL) != 0) {
43018781Sgibbs		if (irq_no != 0) {
43118781Sgibbs			if ((irq_no < ADV_MIN_IRQ_NO) || (irq_no > ADV_MAX_IRQ_NO)) {
43218781Sgibbs				irq_no = 0;
43318781Sgibbs			} else {
43418781Sgibbs				irq_no -= ADV_MIN_IRQ_NO - 1;
43518781Sgibbs			}
43618781Sgibbs		}
43718781Sgibbs		cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFE3;
43818781Sgibbs		cfg_lsw |= 0x0010;
43918781Sgibbs		ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw);
44018781Sgibbs		adv_toggle_irq_act(adv);
44118781Sgibbs
44218781Sgibbs		cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFE0;
44318781Sgibbs		cfg_lsw |= (irq_no & 0x07) << 2;
44418781Sgibbs		ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw);
44518781Sgibbs		adv_toggle_irq_act(adv);
44618781Sgibbs	} else if ((adv->type & ADV_ISA) != 0) {
44718781Sgibbs		if (irq_no == 15)
44818781Sgibbs			irq_no -= 2;
44918781Sgibbs		irq_no -= ADV_MIN_IRQ_NO;
45018781Sgibbs		cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFF3;
45118781Sgibbs		cfg_lsw |= (irq_no & 0x03) << 2;
45218781Sgibbs		ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw);
45318781Sgibbs	}
45418781Sgibbs	return (adv_get_chip_irq(adv));
45518781Sgibbs}
45618781Sgibbs
45718781Sgibbsint
45818781Sgibbsadv_execute_scsi_queue(adv, scsiq)
45918781Sgibbs	struct adv_softc *adv;
46018781Sgibbs	struct adv_scsi_q *scsiq;
46118781Sgibbs{
46218781Sgibbs	int		retval;
46318781Sgibbs	u_int		n_q_required;
46418781Sgibbs	int		s;
46518781Sgibbs	u_int32_t	addr;
46618781Sgibbs	u_int8_t	sg_entry_cnt;
46718781Sgibbs	u_int8_t	target_ix;
46818781Sgibbs	u_int8_t	sg_entry_cnt_minus_one;
46918781Sgibbs	u_int8_t	tid_no;
47018781Sgibbs	u_int8_t	sdtr_data;
47118781Sgibbs	u_int32_t	*p_data_addr;
47218781Sgibbs	u_int32_t	*p_data_bcount;
47318781Sgibbs
47418781Sgibbs	scsiq->q1.q_no = 0;
47518781Sgibbs	retval = 1;  /* Default to error case */
47618781Sgibbs	target_ix = scsiq->q2.target_ix;
47718781Sgibbs	tid_no = ADV_TIX_TO_TID(target_ix);
47818781Sgibbs
47918781Sgibbs	n_q_required = 1;
48018781Sgibbs
48118781Sgibbs	s = splbio();
48218781Sgibbs	if (scsiq->cdbptr->opcode == REQUEST_SENSE) {
48318781Sgibbs		if (((adv->initiate_sdtr & scsiq->q1.target_id) != 0)
48418781Sgibbs		    && ((adv->sdtr_done & scsiq->q1.target_id) != 0)) {
48518781Sgibbs			int sdtr_index;
48618781Sgibbs
48718781Sgibbs			sdtr_data = adv_read_lram_8(adv, ADVV_SDTR_DATA_BEG + tid_no);
48818781Sgibbs			sdtr_index = (sdtr_data >> 4);
48918781Sgibbs			adv_msgout_sdtr(adv, adv_sdtr_period_tbl[sdtr_index],
49018781Sgibbs					 (sdtr_data & ADV_SYN_MAX_OFFSET));
49118781Sgibbs			scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
49218781Sgibbs		}
49318781Sgibbs	}
49418781Sgibbs
49518781Sgibbs	if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
49618781Sgibbs		sg_entry_cnt = scsiq->sg_head->entry_cnt;
49718781Sgibbs		sg_entry_cnt_minus_one = sg_entry_cnt - 1;
49818781Sgibbs
49918781Sgibbs#ifdef DIAGNOSTIC
50018781Sgibbs		if (sg_entry_cnt <= 1)
50118781Sgibbs			panic("adv_execute_scsi_queue: Queue with QC_SG_HEAD set but %d segs.", sg_entry_cnt);
50218781Sgibbs
50318781Sgibbs		if (sg_entry_cnt > ADV_MAX_SG_LIST)
50418781Sgibbs			panic("adv_execute_scsi_queue: Queue with too many segs.");
50518781Sgibbs
50618781Sgibbs		if (adv->type & (ADV_ISA | ADV_VL | ADV_EISA)) {
50718781Sgibbs			for (i = 0; i < sg_entry_cnt_minus_one; i++) {
50818781Sgibbs				addr = scsiq->sg_head->sg_list[i].addr +
50918781Sgibbs				       scsiq->sg_head->sg_list[i].bytes;
51018781Sgibbs
51118781Sgibbs				if ((addr & 0x0003) != 0)
51218781Sgibbs					panic("adv_execute_scsi_queue: SG with odd address or byte count");
51318781Sgibbs			}
51418781Sgibbs		}
51518781Sgibbs#endif
51618781Sgibbs		p_data_addr = &scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].addr;
51718781Sgibbs		p_data_bcount = &scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].bytes;
51818781Sgibbs
51918781Sgibbs		n_q_required = adv_sgcount_to_qcount(sg_entry_cnt);
52018781Sgibbs		scsiq->sg_head->queue_cnt = n_q_required - 1;
52118781Sgibbs	} else {
52218781Sgibbs		p_data_addr = &scsiq->q1.data_addr;
52318781Sgibbs		p_data_bcount = &scsiq->q1.data_cnt;
52418781Sgibbs		n_q_required = 1;
52518781Sgibbs	}
52618781Sgibbs
52718781Sgibbs	if (adv->bug_fix_control & ADV_BUG_FIX_ADD_ONE_BYTE) {
52818781Sgibbs		addr = *p_data_addr + *p_data_bcount;
52918781Sgibbs		if ((addr & 0x0003) != 0) {
53018781Sgibbs			/*
53118781Sgibbs			 * XXX Is this extra test (the one on data_cnt) really only supposed to apply
53218781Sgibbs			 * to the non SG case or was it a bug due to code duplication?
53318781Sgibbs			 */
53418781Sgibbs			if ((scsiq->q1.cntl & QC_SG_HEAD) != 0 || (scsiq->q1.data_cnt & 0x01FF) == 0) {
53518781Sgibbs				if ((scsiq->cdbptr->opcode == READ_COMMAND) ||
53618781Sgibbs				    (scsiq->cdbptr->opcode == READ_BIG)) {
53718781Sgibbs					if ((scsiq->q2.tag_code & ADV_TAG_FLAG_ADD_ONE_BYTE) == 0) {
53818781Sgibbs						(*p_data_bcount)++;
53918781Sgibbs						scsiq->q2.tag_code |= ADV_TAG_FLAG_ADD_ONE_BYTE;
54018781Sgibbs					}
54118781Sgibbs				}
54218781Sgibbs
54318781Sgibbs			}
54418781Sgibbs		}
54518781Sgibbs	}
54618781Sgibbs
54718781Sgibbs	if ((adv_get_num_free_queues(adv, n_q_required) >= n_q_required)
54818781Sgibbs	    || ((scsiq->q1.cntl & QC_URGENT) != 0))
54918781Sgibbs		retval = adv_send_scsi_queue(adv, scsiq, n_q_required);
55018781Sgibbs
55118781Sgibbs	splx(s);
55218781Sgibbs	return (retval);
55318781Sgibbs}
55418781Sgibbs
55518781Sgibbs
55618781Sgibbsu_int8_t
55718781Sgibbsadv_copy_lram_doneq(adv, q_addr, scsiq, max_dma_count)
55818781Sgibbs	struct adv_softc *adv;
55918781Sgibbs	u_int16_t q_addr;
56018781Sgibbs	struct adv_q_done_info *scsiq;
56118781Sgibbs	u_int32_t max_dma_count;
56218781Sgibbs{
56318781Sgibbs	u_int16_t	val;
56418781Sgibbs	u_int8_t	sg_queue_cnt;
56518781Sgibbs
56618781Sgibbs	adv_get_q_info(adv, q_addr + ADV_SCSIQ_DONE_INFO_BEG,
56718781Sgibbs		       (u_int16_t *)scsiq,
56818781Sgibbs		       (sizeof(scsiq->d2) + sizeof(scsiq->d3)) / 2);
56918781Sgibbs
57018781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
57118781Sgibbs	adv_adj_endian_qdone_info(scsiq);
57218781Sgibbs#endif
57318781Sgibbs
57418781Sgibbs	val = adv_read_lram_16(adv, q_addr + ADV_SCSIQ_B_STATUS);
57518781Sgibbs	scsiq->q_status = val & 0xFF;
57618781Sgibbs	scsiq->q_no = (val >> 8) & 0XFF;
57718781Sgibbs
57818781Sgibbs	val = adv_read_lram_16(adv, q_addr + ADV_SCSIQ_B_CNTL);
57918781Sgibbs	scsiq->cntl = val & 0xFF;
58018781Sgibbs	sg_queue_cnt = (val >> 8) & 0xFF;
58118781Sgibbs
58218781Sgibbs	val = adv_read_lram_16(adv,q_addr + ADV_SCSIQ_B_SENSE_LEN);
58318781Sgibbs	scsiq->sense_len = val & 0xFF;
58418781Sgibbs	scsiq->user_def = (val >> 8) & 0xFF;
58518781Sgibbs
58618781Sgibbs	scsiq->remain_bytes = adv_read_lram_32(adv,
58718781Sgibbs					       q_addr + ADV_SCSIQ_DW_REMAIN_XFER_CNT);
58818781Sgibbs	/*
58918781Sgibbs	 * XXX Is this just a safeguard or will the counter really
59018781Sgibbs	 * have bogus upper bits?
59118781Sgibbs	 */
59218781Sgibbs	scsiq->remain_bytes &= max_dma_count;
59318781Sgibbs
59418781Sgibbs	return (sg_queue_cnt);
59518781Sgibbs}
59618781Sgibbs
59718781Sgibbsint
59818781Sgibbsadv_stop_execution(adv)
59918781Sgibbs	struct	adv_softc *adv;
60018781Sgibbs{
60118781Sgibbs	int count;
60218781Sgibbs
60318781Sgibbs	count = 0;
60418781Sgibbs	if (adv_read_lram_8(adv, ADV_STOP_CODE_B) == 0) {
60518781Sgibbs		adv_write_lram_8(adv, ADV_STOP_CODE_B,
60618781Sgibbs				 ADV_STOP_REQ_RISC_STOP);
60718781Sgibbs		do {
60818781Sgibbs			if (adv_read_lram_8(adv, ADV_STOP_CODE_B) &
60918781Sgibbs				ADV_STOP_ACK_RISC_STOP) {
61018781Sgibbs				return (1);
61118781Sgibbs			}
61218781Sgibbs			DELAY(1000);
61318781Sgibbs		} while (count++ < 20);
61418781Sgibbs	}
61518781Sgibbs	return (0);
61618781Sgibbs}
61718781Sgibbs
61818781Sgibbsint
61918781Sgibbsadv_is_chip_halted(adv)
62018781Sgibbs	struct adv_softc *adv;
62118781Sgibbs{
62218781Sgibbs	if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) != 0) {
62318781Sgibbs		if ((ADV_INB(adv, ADV_CHIP_CTRL) & ADV_CC_HALT) != 0) {
62418781Sgibbs			return (1);
62518781Sgibbs		}
62618781Sgibbs	}
62718781Sgibbs	return (0);
62818781Sgibbs}
62918781Sgibbs
63018781Sgibbs/*
63118781Sgibbs * XXX The numeric constants and the loops in this routine
63218781Sgibbs * need to be documented.
63318781Sgibbs */
63418781Sgibbsvoid
63518781Sgibbsadv_ack_interrupt(adv)
63618781Sgibbs	struct adv_softc *adv;
63718781Sgibbs{
63818781Sgibbs	u_int8_t	host_flag;
63918781Sgibbs	u_int8_t	risc_flag;
64018781Sgibbs	int		loop;
64118781Sgibbs
64218781Sgibbs	loop = 0;
64318781Sgibbs	do {
64418781Sgibbs		risc_flag = adv_read_lram_8(adv, ADVV_RISC_FLAG_B);
64518781Sgibbs		if (loop++ > 0x7FFF) {
64618781Sgibbs			break;
64718781Sgibbs		}
64818781Sgibbs	} while ((risc_flag & ADV_RISC_FLAG_GEN_INT) != 0);
64918781Sgibbs
65018781Sgibbs	host_flag = adv_read_lram_8(adv, ADVV_HOST_FLAG_B);
65118781Sgibbs	adv_write_lram_8(adv, ADVV_HOST_FLAG_B,
65218781Sgibbs			 host_flag | ADV_HOST_FLAG_ACK_INT);
65318781Sgibbs
65418781Sgibbs	ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_INT_ACK);
65518781Sgibbs	loop = 0;
65618781Sgibbs	while (ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_INT_PENDING) {
65718781Sgibbs		ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_INT_ACK);
65818781Sgibbs		if (loop++ > 3) {
65918781Sgibbs			break;
66018781Sgibbs		}
66118781Sgibbs	}
66218781Sgibbs
66318781Sgibbs	adv_write_lram_8(adv, ADVV_HOST_FLAG_B, host_flag);
66418781Sgibbs}
66518781Sgibbs
66618781Sgibbs/*
66718781Sgibbs * Handle all conditions that may halt the chip waiting
66818781Sgibbs * for us to intervene.
66918781Sgibbs */
67018781Sgibbsvoid
67118781Sgibbsadv_isr_chip_halted(adv)
67218781Sgibbs	struct adv_softc *adv;
67318781Sgibbs{
67418781Sgibbs	u_int16_t	  int_halt_code;
67518781Sgibbs	u_int8_t	  halt_qp;
67618781Sgibbs	u_int16_t	  halt_q_addr;
67718781Sgibbs	u_int8_t	  target_ix;
67818781Sgibbs	u_int8_t	  q_cntl;
67918781Sgibbs	u_int8_t	  tid_no;
68018781Sgibbs	target_bit_vector target_id;
68118781Sgibbs	target_bit_vector scsi_busy;
68218781Sgibbs	u_int8_t	  asyn_sdtr;
68318781Sgibbs	u_int8_t	  sdtr_data;
68418781Sgibbs
68518781Sgibbs	int_halt_code = adv_read_lram_16(adv, ADVV_HALTCODE_W);
68618781Sgibbs	halt_qp = adv_read_lram_8(adv, ADVV_CURCDB_B);
68718781Sgibbs	halt_q_addr = ADV_QNO_TO_QADDR(halt_qp);
68818781Sgibbs	target_ix = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_TARGET_IX);
68918781Sgibbs	q_cntl = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL);
69018781Sgibbs	tid_no = ADV_TIX_TO_TID(target_ix);
69118781Sgibbs	target_id = ADV_TID_TO_TARGET_ID(tid_no);
69218781Sgibbs	if (adv->needs_async_bug_fix & target_id)
69318781Sgibbs		asyn_sdtr = ASYN_SDTR_DATA_FIX;
69418781Sgibbs	else
69518781Sgibbs		asyn_sdtr = 0;
69618781Sgibbs	if (int_halt_code == ADV_HALT_EXTMSG_IN) {
69718781Sgibbs		struct	sdtr_xmsg sdtr_xmsg;
69818781Sgibbs		int	sdtr_accept;
69918781Sgibbs
70018781Sgibbs		adv_read_lram_16_multi(adv, ADVV_MSGIN_BEG,
70118781Sgibbs					(u_int16_t *) &sdtr_xmsg,
70218781Sgibbs					sizeof(sdtr_xmsg) >> 1);
70318781Sgibbs		if ((sdtr_xmsg.msg_type == MSG_EXTENDED) &&
70418781Sgibbs		    (sdtr_xmsg.msg_len == MSG_EXT_SDTR_LEN)) {
70518781Sgibbs			sdtr_accept = TRUE;
70618781Sgibbs			if (sdtr_xmsg.msg_req == MSG_EXT_SDTR) {
70718781Sgibbs				if (sdtr_xmsg.req_ack_offset > ADV_SYN_MAX_OFFSET) {
70818781Sgibbs
70918781Sgibbs					sdtr_accept = FALSE;
71018781Sgibbs					sdtr_xmsg.req_ack_offset = ADV_SYN_MAX_OFFSET;
71118781Sgibbs				}
71218781Sgibbs				sdtr_data = adv_get_card_sync_setting(sdtr_xmsg.xfer_period,
71318781Sgibbs								      sdtr_xmsg.req_ack_offset);
71418781Sgibbs				if (sdtr_xmsg.req_ack_offset == 0) {
71518781Sgibbs					q_cntl &= ~QC_MSG_OUT;
71618781Sgibbs					adv->initiate_sdtr &= ~target_id;
71718781Sgibbs					adv->sdtr_done &= ~target_id;
71818781Sgibbs					adv_set_chip_sdtr(adv, asyn_sdtr, tid_no);
71918781Sgibbs				} else if (sdtr_data == 0) {
72018781Sgibbs					q_cntl |= QC_MSG_OUT;
72118781Sgibbs					adv->initiate_sdtr &= ~target_id;
72218781Sgibbs					adv->sdtr_done &= ~target_id;
72318781Sgibbs					adv_set_chip_sdtr(adv, asyn_sdtr, tid_no);
72418781Sgibbs				} else {
72518781Sgibbs					if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
72618781Sgibbs						q_cntl &= ~QC_MSG_OUT;
72718781Sgibbs						adv->sdtr_done |= target_id;
72818781Sgibbs						adv->initiate_sdtr |= target_id;
72918781Sgibbs						adv->needs_async_bug_fix &= ~target_id;
73018781Sgibbs						adv_set_chip_sdtr(adv, sdtr_data, tid_no);
73118781Sgibbs					} else {
73218781Sgibbs
73318781Sgibbs						q_cntl |= QC_MSG_OUT;
73418781Sgibbs
73518781Sgibbs						adv_msgout_sdtr(adv,
73618781Sgibbs								sdtr_xmsg.xfer_period,
73718781Sgibbs								sdtr_xmsg.req_ack_offset);
73818781Sgibbs						adv->needs_async_bug_fix &= ~target_id;
73918781Sgibbs						adv_set_chip_sdtr(adv, sdtr_data, tid_no);
74018781Sgibbs						adv->sdtr_done |= target_id;
74118781Sgibbs						adv->initiate_sdtr |= target_id;
74218781Sgibbs					}
74318781Sgibbs				}
74418781Sgibbs
74518781Sgibbs				adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl);
74618781Sgibbs			}
74718781Sgibbs		}
74818781Sgibbs		/*
74918781Sgibbs		 * XXX Hey, shouldn't we be rejecting any messages we don't understand?
75018781Sgibbs		 *     The old code also did not un-halt the processor if it recieved
75118781Sgibbs		 *     an extended message that it didn't understand.  That didn't
75218781Sgibbs		 *     seem right, so I changed this routine to always un-halt the
75318781Sgibbs		 *     processor at the end.
75418781Sgibbs		 */
75518781Sgibbs	} else if (int_halt_code == ADV_HALT_CHK_CONDITION) {
75618781Sgibbs		u_int8_t	tag_code;
75718781Sgibbs		u_int8_t	q_status;
75818781Sgibbs
75918781Sgibbs		q_cntl |= QC_REQ_SENSE;
76018781Sgibbs		if (((adv->initiate_sdtr & target_id) != 0) &&
76118781Sgibbs			((adv->sdtr_done & target_id) != 0)) {
76218781Sgibbs
76318781Sgibbs			sdtr_data = adv_read_lram_8(adv, ADVV_SDTR_DATA_BEG + tid_no);
76418781Sgibbs			/* XXX Macrotize the extraction of the index from sdtr_data ??? */
76518781Sgibbs			adv_msgout_sdtr(adv, adv_sdtr_period_tbl[(sdtr_data >> 4) & 0x0F],
76618781Sgibbs					sdtr_data & ADV_SYN_MAX_OFFSET);
76718781Sgibbs			q_cntl |= QC_MSG_OUT;
76818781Sgibbs		}
76918781Sgibbs		adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl);
77018781Sgibbs
77118781Sgibbs		/* Don't tag request sense commands */
77218781Sgibbs		tag_code = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_TAG_CODE);
77318781Sgibbs		tag_code &= ~(MSG_SIMPLE_Q_TAG|MSG_HEAD_OF_Q_TAG|MSG_ORDERED_Q_TAG);
77418781Sgibbs		adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_TAG_CODE, tag_code);
77518781Sgibbs
77618781Sgibbs		q_status = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_STATUS);
77718781Sgibbs		q_status |= (QS_READY | QS_BUSY);
77818781Sgibbs		adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_STATUS, q_status);
77918781Sgibbs
78018781Sgibbs		scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B);
78118781Sgibbs		scsi_busy &= ~target_id;
78218781Sgibbs		adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy);
78318781Sgibbs	} else if (int_halt_code == ADV_HALT_SDTR_REJECTED) {
78418781Sgibbs		struct	sdtr_xmsg out_msg;
78518781Sgibbs
78618781Sgibbs		adv_read_lram_16_multi(adv, ADVV_MSGOUT_BEG,
78718781Sgibbs				       (u_int16_t *) &out_msg,
78818781Sgibbs				       sizeof(out_msg)/2);
78918781Sgibbs
79018781Sgibbs		if ((out_msg.msg_type == MSG_EXTENDED) &&
79118781Sgibbs			(out_msg.msg_len == MSG_EXT_SDTR_LEN) &&
79218781Sgibbs			(out_msg.msg_req == MSG_EXT_SDTR)) {
79318781Sgibbs
79418781Sgibbs			adv->initiate_sdtr &= ~target_id;
79518781Sgibbs			adv->sdtr_done &= ~target_id;
79618781Sgibbs			adv_set_chip_sdtr(adv, asyn_sdtr, tid_no);
79718781Sgibbs		}
79818781Sgibbs		q_cntl &= ~QC_MSG_OUT;
79918781Sgibbs		adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl);
80018781Sgibbs	} else if (int_halt_code == ADV_HALT_SS_QUEUE_FULL) {
80118781Sgibbs		u_int8_t	cur_dvc_qng;
80218781Sgibbs		u_int8_t	scsi_status;
80318781Sgibbs
80418781Sgibbs		/*
80518781Sgibbs		 * XXX It would be nice if we could push the responsibility for handling
80618781Sgibbs		 *     this situation onto the generic SCSI layer as other drivers do.
80718781Sgibbs		 *     This would be done by completing the command with the status byte
80818781Sgibbs		 *     set to QUEUE_FULL, whereupon it will request that any transactions
80918781Sgibbs		 *     pending on the target that where scheduled after this one be aborted
81018781Sgibbs		 *     (so as to maintain queue ordering) and the number of requests the
81118781Sgibbs		 *     upper level will attempt to send this target will be reduced.
81218781Sgibbs		 *
81318781Sgibbs		 *     With this current strategy, am I guaranteed that once I unbusy the
81418781Sgibbs		 *     target the queued up transactions will be sent in the order they
81518781Sgibbs		 *     were queued?  If the ASC chip does a round-robin on all queued
81618781Sgibbs		 *     transactions looking for queues to run, the order is not guaranteed.
81718781Sgibbs		 */
81818781Sgibbs		scsi_status = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_SCSI_STATUS);
81918781Sgibbs		cur_dvc_qng = adv_read_lram_8(adv, ADV_QADR_BEG + target_ix);
82018781Sgibbs		printf("adv%d: Queue full - target %d, active transactions %d\n", adv->unit,
82118781Sgibbs		       tid_no, cur_dvc_qng);
82218781Sgibbs#if 0
82318781Sgibbs		/* XXX FIX LATER */
82418781Sgibbs		if ((cur_dvc_qng > 0) && (adv->cur_dvc_qng[tid_no] > 0)) {
82518781Sgibbs			scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B);
82618781Sgibbs			scsi_busy |= target_id;
82718781Sgibbs			adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy);
82818781Sgibbs			asc_dvc->queue_full_or_busy |= target_id;
82918781Sgibbs
83018781Sgibbs			if (scsi_status == SS_QUEUE_FULL) {
83118781Sgibbs				if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
83218781Sgibbs					cur_dvc_qng -= 1;
83318781Sgibbs					asc_dvc->max_dvc_qng[tid_no] = cur_dvc_qng;
83418781Sgibbs
83518781Sgibbs					adv_write_lram_8(adv, ADVV_MAX_DVC_QNG_BEG + tid_no,
83618781Sgibbs							 cur_dvc_qng);
83718781Sgibbs				}
83818781Sgibbs			}
83918781Sgibbs		}
84018781Sgibbs#endif
84118781Sgibbs	}
84218781Sgibbs	adv_write_lram_16(adv, ADVV_HALTCODE_W, 0);
84318781Sgibbs}
84418781Sgibbs
84518781Sgibbs/* Internal Routines */
84618781Sgibbs
84718781Sgibbsstatic void
84818781Sgibbsadv_read_lram_16_multi(adv, s_addr, buffer, count)
84918781Sgibbs	struct adv_softc *adv;
85018781Sgibbs	u_int16_t	 s_addr;
85118781Sgibbs	u_int16_t	 *buffer;
85218781Sgibbs	int		 count;
85318781Sgibbs{
85418781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
85518781Sgibbs	ADV_INSW(adv, ADV_LRAM_DATA, buffer, count);
85618781Sgibbs}
85718781Sgibbs
85818781Sgibbsstatic void
85918781Sgibbsadv_write_lram_16_multi(adv, s_addr, buffer, count)
86018781Sgibbs	struct adv_softc *adv;
86118781Sgibbs	u_int16_t	 s_addr;
86218781Sgibbs	u_int16_t	 *buffer;
86318781Sgibbs	int		 count;
86418781Sgibbs{
86518781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
86618781Sgibbs	ADV_OUTSW(adv, ADV_LRAM_DATA, buffer, count);
86718781Sgibbs}
86818781Sgibbs
86918781Sgibbsstatic void
87018781Sgibbsadv_mset_lram_16(adv, s_addr, set_value, count)
87118781Sgibbs	struct adv_softc *adv;
87218781Sgibbs	u_int16_t s_addr;
87318781Sgibbs	u_int16_t set_value;
87418781Sgibbs	int count;
87518781Sgibbs{
87618781Sgibbs	int	i;
87718781Sgibbs
87818781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
87918781Sgibbs	for (i = 0; i < count; i++)
88018781Sgibbs		ADV_OUTW(adv, ADV_LRAM_DATA, set_value);
88118781Sgibbs}
88218781Sgibbs
88318781Sgibbsstatic u_int32_t
88418781Sgibbsadv_msum_lram_16(adv, s_addr, count)
88518781Sgibbs	struct adv_softc *adv;
88618781Sgibbs	u_int16_t	 s_addr;
88718781Sgibbs	int		 count;
88818781Sgibbs{
88918781Sgibbs	u_int32_t	sum;
89018781Sgibbs	int		i;
89118781Sgibbs
89218781Sgibbs	sum = 0;
89318781Sgibbs	for (i = 0; i < count; i++, s_addr += 2)
89418781Sgibbs		sum += adv_read_lram_16(adv, s_addr);
89518781Sgibbs	return (sum);
89618781Sgibbs}
89718781Sgibbs
89818781Sgibbsstatic int
89918781Sgibbsadv_write_and_verify_lram_16(adv, addr, value)
90018781Sgibbs	struct adv_softc *adv;
90118781Sgibbs	u_int16_t addr;
90218781Sgibbs	u_int16_t value;
90318781Sgibbs{
90418781Sgibbs	int	retval;
90518781Sgibbs
90618781Sgibbs	retval = 0;
90718781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
90818781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, value);
90918781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
91018781Sgibbs	if (value != ADV_INW(adv, ADV_LRAM_DATA))
91118781Sgibbs		retval = 1;
91218781Sgibbs	return (retval);
91318781Sgibbs}
91418781Sgibbs
91518781Sgibbsstatic u_int32_t
91618781Sgibbsadv_read_lram_32(adv, addr)
91718781Sgibbs	struct adv_softc *adv;
91818781Sgibbs	u_int16_t addr;
91918781Sgibbs{
92018781Sgibbs	u_int16_t           val_low, val_high;
92118781Sgibbs
92218781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
92318781Sgibbs
92418781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
92518781Sgibbs	val_high = ADV_INW(adv, ADV_LRAM_DATA);
92618781Sgibbs	val_low = ADV_INW(adv, ADV_LRAM_DATA);
92718781Sgibbs#else
92818781Sgibbs	val_low = ADV_INW(adv, ADV_LRAM_DATA);
92918781Sgibbs	val_high = ADV_INW(adv, ADV_LRAM_DATA);
93018781Sgibbs#endif
93118781Sgibbs
93218781Sgibbs	return (((u_int32_t)val_high << 16) | (u_int32_t)val_low);
93318781Sgibbs}
93418781Sgibbs
93518781Sgibbsstatic void
93618781Sgibbsadv_write_lram_32(adv, addr, value)
93718781Sgibbs	struct adv_softc *adv;
93818781Sgibbs	u_int16_t addr;
93918781Sgibbs	u_int32_t value;
94018781Sgibbs{
94118781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
94218781Sgibbs
94318781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
94418781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)((value >> 16) & 0xFFFF));
94518781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)(value & 0xFFFF));
94618781Sgibbs#else
94718781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)(value & 0xFFFF));
94818781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)((value >> 16) & 0xFFFF));
94918781Sgibbs#endif
95018781Sgibbs}
95118781Sgibbs
95218781Sgibbsstatic void
95318781Sgibbsadv_write_lram_32_multi(adv, s_addr, buffer, count)
95418781Sgibbs	struct adv_softc *adv;
95518781Sgibbs	u_int16_t s_addr;
95618781Sgibbs	u_int32_t *buffer;
95718781Sgibbs	int count;
95818781Sgibbs{
95918781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
96018781Sgibbs	ADV_OUTSW(adv, ADV_LRAM_DATA, buffer, count * 2);
96118781Sgibbs}
96218781Sgibbs
96318781Sgibbsstatic u_int16_t
96418781Sgibbsadv_read_eeprom_16(adv, addr)
96518781Sgibbs	struct adv_softc *adv;
96618781Sgibbs	u_int8_t addr;
96718781Sgibbs{
96818781Sgibbs	u_int16_t read_wval;
96918781Sgibbs	u_int8_t  cmd_reg;
97018781Sgibbs
97118781Sgibbs	adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_DISABLE);
97218781Sgibbs	DELAY(1000);
97318781Sgibbs	cmd_reg = addr | ADV_EEPROM_CMD_READ;
97418781Sgibbs	adv_write_eeprom_cmd_reg(adv, cmd_reg);
97518781Sgibbs	DELAY(1000);
97618781Sgibbs	read_wval = ADV_INW(adv, ADV_EEPROM_DATA);
97718781Sgibbs	DELAY(1000);
97818781Sgibbs	return (read_wval);
97918781Sgibbs}
98018781Sgibbs
98118781Sgibbsstatic u_int16_t
98218781Sgibbsadv_write_eeprom_16(adv, addr, value)
98318781Sgibbs	struct adv_softc *adv;
98418781Sgibbs	u_int8_t addr;
98518781Sgibbs	u_int16_t value;
98618781Sgibbs{
98718781Sgibbs	u_int16_t	read_value;
98818781Sgibbs
98918781Sgibbs	read_value = adv_read_eeprom_16(adv, addr);
99018781Sgibbs	if (read_value != value) {
99118781Sgibbs		adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_ENABLE);
99218781Sgibbs		DELAY(1000);
99318781Sgibbs
99418781Sgibbs		ADV_OUTW(adv, ADV_EEPROM_DATA, value);
99518781Sgibbs		DELAY(1000);
99618781Sgibbs
99718781Sgibbs		adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE | addr);
99818781Sgibbs		DELAY(20 * 1000);
99918781Sgibbs
100018781Sgibbs		adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_DISABLE);
100118781Sgibbs		DELAY(1000);
100218781Sgibbs		read_value = adv_read_eeprom_16(adv, addr);
100318781Sgibbs	}
100418781Sgibbs	return (read_value);
100518781Sgibbs}
100618781Sgibbs
100718781Sgibbsstatic int
100818781Sgibbsadv_write_eeprom_cmd_reg(adv, cmd_reg)
100918781Sgibbs	struct adv_softc *adv;
101018781Sgibbs	u_int8_t cmd_reg;
101118781Sgibbs{
101218781Sgibbs	u_int8_t read_back;
101318781Sgibbs	int	 retry;
101418781Sgibbs
101518781Sgibbs	retry = 0;
101618781Sgibbs	while (1) {
101718781Sgibbs		ADV_OUTB(adv, ADV_EEPROM_CMD, cmd_reg);
101818781Sgibbs		DELAY(1000);
101918781Sgibbs		read_back = ADV_INB(adv, ADV_EEPROM_CMD);
102018781Sgibbs		if (read_back == cmd_reg) {
102118781Sgibbs			return (1);
102218781Sgibbs		}
102318781Sgibbs		if (retry++ > ADV_EEPROM_MAX_RETRY) {
102418781Sgibbs			return (0);
102518781Sgibbs		}
102618781Sgibbs	}
102718781Sgibbs}
102818781Sgibbs
102918781Sgibbsstatic int
103018781Sgibbsadv_set_eeprom_config_once(adv, eeprom_config)
103118781Sgibbs	struct adv_softc *adv;
103218781Sgibbs	struct adv_eeprom_config *eeprom_config;
103318781Sgibbs{
103418781Sgibbs	int		n_error;
103518781Sgibbs	u_int16_t	*wbuf;
103618781Sgibbs	u_int16_t	sum;
103718781Sgibbs	u_int8_t	s_addr;
103818781Sgibbs	u_int8_t	cfg_beg;
103918781Sgibbs	u_int8_t	cfg_end;
104018781Sgibbs
104118781Sgibbs	wbuf = (u_int16_t *)eeprom_config;
104218781Sgibbs	n_error = 0;
104318781Sgibbs	sum = 0;
104418781Sgibbs	for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
104518781Sgibbs		sum += *wbuf;
104618781Sgibbs		if (*wbuf != adv_write_eeprom_16(adv, s_addr, *wbuf)) {
104718781Sgibbs			n_error++;
104818781Sgibbs		}
104918781Sgibbs	}
105018781Sgibbs	if (adv->type & ADV_VL) {
105118781Sgibbs		cfg_beg = ADV_EEPROM_CFG_BEG_VL;
105218781Sgibbs		cfg_end = ADV_EEPROM_MAX_ADDR_VL;
105318781Sgibbs	} else {
105418781Sgibbs		cfg_beg = ADV_EEPROM_CFG_BEG;
105518781Sgibbs		cfg_end = ADV_EEPROM_MAX_ADDR;
105618781Sgibbs	}
105718781Sgibbs
105818781Sgibbs	for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
105918781Sgibbs		sum += *wbuf;
106018781Sgibbs		if (*wbuf != adv_write_eeprom_16(adv, s_addr, *wbuf)) {
106118781Sgibbs			n_error++;
106218781Sgibbs		}
106318781Sgibbs	}
106418781Sgibbs	*wbuf = sum;
106518781Sgibbs	if (sum != adv_write_eeprom_16(adv, s_addr, sum)) {
106618781Sgibbs		n_error++;
106718781Sgibbs	}
106818781Sgibbs	wbuf = (u_int16_t *)eeprom_config;
106918781Sgibbs	for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
107018781Sgibbs		if (*wbuf != adv_read_eeprom_16(adv, s_addr)) {
107118781Sgibbs			n_error++;
107218781Sgibbs		}
107318781Sgibbs	}
107418781Sgibbs	for (s_addr = cfg_beg; s_addr <= cfg_end; s_addr++, wbuf++) {
107518781Sgibbs		if (*wbuf != adv_read_eeprom_16(adv, s_addr)) {
107618781Sgibbs			n_error++;
107718781Sgibbs		}
107818781Sgibbs	}
107918781Sgibbs	return (n_error);
108018781Sgibbs}
108118781Sgibbs
108218781Sgibbsstatic u_int32_t
108318781Sgibbsadv_load_microcode(adv, s_addr, mcode_buf, mcode_size)
108418781Sgibbs	struct adv_softc *adv;
108518781Sgibbs	u_int16_t	 s_addr;
108618781Sgibbs	u_int16_t	 *mcode_buf;
108718781Sgibbs	u_int16_t	 mcode_size;
108818781Sgibbs{
108918781Sgibbs	u_int32_t	chksum;
109018781Sgibbs	u_int16_t	mcode_lram_size;
109118781Sgibbs	u_int16_t	mcode_chksum;
109218781Sgibbs
109318781Sgibbs	mcode_lram_size = mcode_size >> 1;
109418781Sgibbs	/* XXX Why zero the memory just before you write the whole thing?? */
109518781Sgibbs	/* adv_mset_lram_16(adv, s_addr, 0, mcode_lram_size);*/
109618781Sgibbs	adv_write_lram_16_multi(adv, s_addr, mcode_buf, mcode_lram_size);
109718781Sgibbs
109818781Sgibbs	chksum = adv_msum_lram_16(adv, s_addr, mcode_lram_size);
109918781Sgibbs	mcode_chksum = (u_int16_t)adv_msum_lram_16(adv, ADV_CODE_SEC_BEG,
110018781Sgibbs					  ((mcode_size - s_addr - ADV_CODE_SEC_BEG) >> 1));
110118781Sgibbs	adv_write_lram_16(adv, ADVV_MCODE_CHKSUM_W, mcode_chksum);
110218781Sgibbs	adv_write_lram_16(adv, ADVV_MCODE_SIZE_W, mcode_size);
110318781Sgibbs	return (chksum);
110418781Sgibbs}
110518781Sgibbs
110618781Sgibbsstatic void
110718781Sgibbsadv_init_lram(adv)
110818781Sgibbs	struct adv_softc *adv;
110918781Sgibbs{
111018781Sgibbs	u_int8_t	i;
111118781Sgibbs	u_int16_t	s_addr;
111218781Sgibbs
111318781Sgibbs	adv_mset_lram_16(adv, ADV_QADR_BEG, 0,
111418781Sgibbs			 (u_int16_t)((((int)adv->max_openings + 2 + 1) * 64) >> 1));
111518781Sgibbs
111618781Sgibbs	i = ADV_MIN_ACTIVE_QNO;
111718781Sgibbs	s_addr = ADV_QADR_BEG + ADV_QBLK_SIZE;
111818781Sgibbs
111918781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD,	i + 1);
112018781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, adv->max_openings);
112118781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i);
112218781Sgibbs	i++;
112318781Sgibbs	s_addr += ADV_QBLK_SIZE;
112418781Sgibbs	for (; i < adv->max_openings; i++, s_addr += ADV_QBLK_SIZE) {
112518781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i + 1);
112618781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, i - 1);
112718781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i);
112818781Sgibbs	}
112918781Sgibbs
113018781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, ADV_QLINK_END);
113118781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, adv->max_openings - 1);
113218781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, adv->max_openings);
113318781Sgibbs	i++;
113418781Sgibbs	s_addr += ADV_QBLK_SIZE;
113518781Sgibbs
113618781Sgibbs	for (; i <= adv->max_openings + 3; i++, s_addr += ADV_QBLK_SIZE) {
113718781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i);
113818781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, i);
113918781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i);
114018781Sgibbs	}
114118781Sgibbs}
114218781Sgibbs
114318781Sgibbsstatic int
114418781Sgibbsadv_init_microcode_var(adv)
114518781Sgibbs	struct adv_softc *adv;
114618781Sgibbs{
114718781Sgibbs	int       i;
114818781Sgibbs
114918781Sgibbs	for (i = 0; i <= ADV_MAX_TID; i++) {
115018781Sgibbs		adv_write_lram_8(adv, ADVV_SDTR_DATA_BEG + i,
115118781Sgibbs				 adv->sdtr_data[i]);
115218781Sgibbs	}
115318781Sgibbs
115418781Sgibbs	adv_init_qlink_var(adv);
115518781Sgibbs
115618781Sgibbs	/* XXX Again, what about wide busses??? */
115718781Sgibbs	adv_write_lram_8(adv, ADVV_DISC_ENABLE_B, adv->disc_enable);
115818781Sgibbs	adv_write_lram_8(adv, ADVV_HOSTSCSI_ID_B, 0x01 << adv->scsi_id);
115918781Sgibbs
116018781Sgibbs	/* What are the extra 8 bytes for?? */
116118781Sgibbs	adv_write_lram_32(adv, ADVV_OVERRUN_PADDR_D, vtophys(&(adv->overrun_buf[0])) + 8);
116218781Sgibbs
116318781Sgibbs	adv_write_lram_32(adv, ADVV_OVERRUN_BSIZE_D, ADV_OVERRUN_BSIZE - 8);
116418781Sgibbs
116518781Sgibbs#if 0
116618781Sgibbs	/* If we're going to print anything, RCS ids are more meaningful */
116718781Sgibbs	mcode_date = adv_read_lram_16(adv, ADVV_MC_DATE_W);
116818781Sgibbs	mcode_version = adv_read_lram_16(adv, ADVV_MC_VER_W);
116918781Sgibbs#endif
117018781Sgibbs	ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR);
117118781Sgibbs	if (ADV_INW(adv, ADV_REG_PROG_COUNTER) != ADV_MCODE_START_ADDR) {
117218781Sgibbs		printf("adv%d: Unable to set program counter. Aborting.\n", adv->unit);
117318781Sgibbs		return (1);
117418781Sgibbs	}
117518781Sgibbs	if (adv_start_chip(adv) != 1) {
117618781Sgibbs		printf("adv%d: Unable to start on board processor. Aborting.\n",
117718781Sgibbs		       adv->unit);
117818781Sgibbs		return (1);
117918781Sgibbs	}
118018781Sgibbs	return (0);
118118781Sgibbs}
118218781Sgibbs
118318781Sgibbsstatic void
118418781Sgibbsadv_init_qlink_var(adv)
118518781Sgibbs	struct adv_softc *adv;
118618781Sgibbs{
118718781Sgibbs	int	  i;
118818781Sgibbs	u_int16_t lram_addr;
118918781Sgibbs
119018781Sgibbs	adv_write_lram_8(adv, ADVV_NEXTRDY_B, 1);
119118781Sgibbs	adv_write_lram_8(adv, ADVV_DONENEXT_B, adv->max_openings);
119218781Sgibbs
119318781Sgibbs	adv_write_lram_16(adv, ADVV_FREE_Q_HEAD_W, 1);
119418781Sgibbs	adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, adv->max_openings);
119518781Sgibbs
119618781Sgibbs	adv_write_lram_8(adv, ADVV_BUSY_QHEAD_B,
119718781Sgibbs			 (u_int8_t)((int) adv->max_openings + 1));
119818781Sgibbs	adv_write_lram_8(adv, ADVV_DISC1_QHEAD_B,
119918781Sgibbs			 (u_int8_t)((int) adv->max_openings + 2));
120018781Sgibbs
120118781Sgibbs	adv_write_lram_8(adv, ADVV_TOTAL_READY_Q_B, adv->max_openings);
120218781Sgibbs
120318781Sgibbs	adv_write_lram_16(adv, ADVV_ASCDVC_ERR_CODE_W, 0);
120418781Sgibbs	adv_write_lram_16(adv, ADVV_HALTCODE_W, 0);
120518781Sgibbs	adv_write_lram_8(adv, ADVV_STOP_CODE_B, 0);
120618781Sgibbs	adv_write_lram_8(adv, ADVV_SCSIBUSY_B, 0);
120718781Sgibbs	adv_write_lram_8(adv, ADVV_WTM_FLAG_B, 0);
120818781Sgibbs
120918781Sgibbs	adv_write_lram_8(adv, ADVV_CDBCNT_B, 0);
121018781Sgibbs
121118781Sgibbs	lram_addr = ADV_QADR_BEG;
121218781Sgibbs	for (i = 0; i < 32; i++, lram_addr += 2)
121318781Sgibbs		adv_write_lram_16(adv, lram_addr, 0);
121418781Sgibbs}
121518781Sgibbsstatic void
121618781Sgibbsadv_disable_interrupt(adv)
121718781Sgibbs	struct adv_softc *adv;
121818781Sgibbs{
121918781Sgibbs	u_int16_t cfg;
122018781Sgibbs
122118781Sgibbs	cfg = ADV_INW(adv, ADV_CONFIG_LSW);
122218781Sgibbs	ADV_OUTW(adv, ADV_CONFIG_LSW, cfg & ~ADV_CFG_LSW_HOST_INT_ON);
122318781Sgibbs}
122418781Sgibbs
122518781Sgibbsstatic void
122618781Sgibbsadv_enable_interrupt(adv)
122718781Sgibbs	struct adv_softc *adv;
122818781Sgibbs{
122918781Sgibbs	u_int16_t cfg;
123018781Sgibbs
123118781Sgibbs	cfg = ADV_INW(adv, ADV_CONFIG_LSW);
123218781Sgibbs	ADV_OUTW(adv, ADV_CONFIG_LSW, cfg | ADV_CFG_LSW_HOST_INT_ON);
123318781Sgibbs}
123418781Sgibbs
123518781Sgibbsstatic void
123618781Sgibbsadv_toggle_irq_act(adv)
123718781Sgibbs	struct adv_softc *adv;
123818781Sgibbs{
123918781Sgibbs	ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_IRQ_ACT);
124018781Sgibbs	ADV_OUTW(adv, ADV_CHIP_STATUS, 0);
124118781Sgibbs}
124218781Sgibbs
124318781Sgibbs#if UNUSED
124418781Sgibbsstatic void
124518781Sgibbsadv_start_execution(adv)
124618781Sgibbs	struct adv_softc *adv;
124718781Sgibbs{
124818781Sgibbs	if (adv_read_lram_8(adv, ADV_STOP_CODE_B) != 0) {
124918781Sgibbs		adv_write_lram_8(adv, ADV_STOP_CODE_B, 0);
125018781Sgibbs	}
125118781Sgibbs}
125218781Sgibbs#endif
125318781Sgibbs
125418781Sgibbsstatic int
125518781Sgibbsadv_start_chip(adv)
125618781Sgibbs	struct adv_softc *adv;
125718781Sgibbs{
125818781Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, 0);
125918781Sgibbs	if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) != 0)
126018781Sgibbs		return (0);
126118781Sgibbs	return (1);
126218781Sgibbs}
126318781Sgibbs
126418781Sgibbsstatic int
126518781Sgibbsadv_stop_chip(adv)
126618781Sgibbs	struct adv_softc *adv;
126718781Sgibbs{
126818781Sgibbs	u_int8_t cc_val;
126918781Sgibbs
127018781Sgibbs	cc_val = ADV_INB(adv, ADV_CHIP_CTRL)
127118781Sgibbs		 & (~(ADV_CC_SINGLE_STEP | ADV_CC_TEST | ADV_CC_DIAG));
127218781Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, cc_val | ADV_CC_HALT);
127318781Sgibbs	adv_set_chip_ih(adv, ADV_INS_HALT);
127418781Sgibbs	adv_set_chip_ih(adv, ADV_INS_RFLAG_WTM);
127518781Sgibbs	if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) == 0) {
127618781Sgibbs		return (0);
127718781Sgibbs	}
127818781Sgibbs	return (1);
127918781Sgibbs}
128018781Sgibbs
128118781Sgibbsstatic void
128218781Sgibbsadv_set_chip_ih(adv, ins_code)
128318781Sgibbs	struct adv_softc *adv;
128418781Sgibbs	u_int16_t ins_code;
128518781Sgibbs{
128618781Sgibbs	adv_set_bank(adv, 1);
128718781Sgibbs	ADV_OUTW(adv, ADV_REG_IH, ins_code);
128818781Sgibbs	adv_set_bank(adv, 0);
128918781Sgibbs}
129018781Sgibbs
129118781Sgibbsstatic void
129218781Sgibbsadv_set_bank(adv, bank)
129318781Sgibbs	struct adv_softc *adv;
129418781Sgibbs	u_int8_t bank;
129518781Sgibbs{
129618781Sgibbs	u_int8_t control;
129718781Sgibbs
129818781Sgibbs	/*
129918781Sgibbs	 * Start out with the bank reset to 0
130018781Sgibbs	 */
130118781Sgibbs	control = ADV_INB(adv, ADV_CHIP_CTRL)
130218781Sgibbs		  &  (~(ADV_CC_SINGLE_STEP | ADV_CC_TEST
130318781Sgibbs			| ADV_CC_DIAG | ADV_CC_SCSI_RESET
130418781Sgibbs			| ADV_CC_CHIP_RESET | ADV_CC_BANK_ONE));
130518781Sgibbs	if (bank == 1) {
130618781Sgibbs		control |= ADV_CC_BANK_ONE;
130718781Sgibbs	} else if (bank == 2) {
130818781Sgibbs		control |= ADV_CC_DIAG | ADV_CC_BANK_ONE;
130918781Sgibbs	}
131018781Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, control);
131118781Sgibbs}
131218781Sgibbs
131318781Sgibbs#if UNUSED
131418781Sgibbsstatic u_int8_t
131518781Sgibbsadv_get_chip_scsi_ctrl(adv)
131618781Sgibbs	struct	adv_softc *adv;
131718781Sgibbs{
131818781Sgibbs	u_int8_t scsi_ctrl;
131918781Sgibbs
132018781Sgibbs	adv_set_bank(adv, 1);
132118781Sgibbs	scsi_ctrl = ADV_INB(adv, ADV_REG_SC);
132218781Sgibbs	adv_set_bank(adv, 0);
132318781Sgibbs	return (scsi_ctrl);
132418781Sgibbs}
132518781Sgibbs#endif
132618781Sgibbs
132718781Sgibbsstatic int
132818781Sgibbsadv_sgcount_to_qcount(sgcount)
132918781Sgibbs	int sgcount;
133018781Sgibbs{
133118781Sgibbs	int	n_sg_list_qs;
133218781Sgibbs
133318781Sgibbs	n_sg_list_qs = ((sgcount - 1) / ADV_SG_LIST_PER_Q);
133418781Sgibbs	if (((sgcount - 1) % ADV_SG_LIST_PER_Q) != 0)
133518781Sgibbs		n_sg_list_qs++;
133618781Sgibbs	return (n_sg_list_qs + 1);
133718781Sgibbs}
133818781Sgibbs
133918781Sgibbs/*
134018781Sgibbs * XXX Looks like more padding issues in this routine as well.
134118781Sgibbs *     There has to be a way to turn this into an insw.
134218781Sgibbs */
134318781Sgibbsstatic void
134418781Sgibbsadv_get_q_info(adv, s_addr, inbuf, words)
134518781Sgibbs	struct adv_softc *adv;
134618781Sgibbs	u_int16_t s_addr;
134718781Sgibbs	u_int16_t *inbuf;
134818781Sgibbs	int words;
134918781Sgibbs{
135018781Sgibbs	int	i;
135118781Sgibbs
135218781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
135318781Sgibbs	for (i = 0; i < words; i++, inbuf++) {
135418781Sgibbs		if (i == 5) {
135518781Sgibbs			continue;
135618781Sgibbs		}
135718781Sgibbs		*inbuf = ADV_INW(adv, ADV_LRAM_DATA);
135818781Sgibbs	}
135918781Sgibbs}
136018781Sgibbs
136118781Sgibbsstatic u_int
136218781Sgibbsadv_get_num_free_queues(adv, n_qs)
136318781Sgibbs	struct adv_softc *adv;
136418781Sgibbs	u_int8_t n_qs;
136518781Sgibbs{
136618781Sgibbs	u_int	  cur_used_qs;
136718781Sgibbs	u_int	  cur_free_qs;
136818781Sgibbs
136918781Sgibbs	if (n_qs == 1)
137018781Sgibbs		cur_used_qs = adv->cur_active +
137118781Sgibbs			      adv->openings_needed +
137218781Sgibbs			      ADV_MIN_FREE_Q;
137318781Sgibbs	else
137418781Sgibbs		cur_used_qs = adv->cur_active +
137518781Sgibbs			      ADV_MIN_FREE_Q;
137618781Sgibbs
137718781Sgibbs	if ((cur_used_qs + n_qs) <= adv->max_openings) {
137818781Sgibbs		cur_free_qs = adv->max_openings - cur_used_qs;
137918781Sgibbs		return (cur_free_qs);
138018781Sgibbs	}
138118781Sgibbs	if (n_qs > 1)
138218781Sgibbs		if (n_qs > adv->openings_needed)
138318781Sgibbs			adv->openings_needed = n_qs;
138418781Sgibbs	return (0);
138518781Sgibbs}
138618781Sgibbs
138718781Sgibbsstatic u_int8_t
138818781Sgibbsadv_alloc_free_queues(adv, free_q_head, n_free_q)
138918781Sgibbs	struct adv_softc *adv;
139018781Sgibbs	u_int8_t free_q_head;
139118781Sgibbs	u_int8_t n_free_q;
139218781Sgibbs{
139318781Sgibbs	int i;
139418781Sgibbs
139518781Sgibbs	for (i = 0; i < n_free_q; i++) {
139618781Sgibbs		free_q_head = adv_alloc_free_queue(adv, free_q_head);
139718781Sgibbs		if (free_q_head == ADV_QLINK_END)
139818781Sgibbs			break;
139918781Sgibbs	}
140018781Sgibbs	return (free_q_head);
140118781Sgibbs}
140218781Sgibbs
140318781Sgibbsstatic u_int8_t
140418781Sgibbsadv_alloc_free_queue(adv, free_q_head)
140518781Sgibbs	struct adv_softc *adv;
140618781Sgibbs	u_int8_t free_q_head;
140718781Sgibbs{
140818781Sgibbs	u_int16_t	q_addr;
140918781Sgibbs	u_int8_t	next_qp;
141018781Sgibbs	u_int8_t	q_status;
141118781Sgibbs
141218781Sgibbs	next_qp = ADV_QLINK_END;
141318781Sgibbs	q_addr = ADV_QNO_TO_QADDR(free_q_head);
141418781Sgibbs	q_status = adv_read_lram_8(adv,	q_addr + ADV_SCSIQ_B_STATUS);
141518781Sgibbs
141618781Sgibbs	if ((q_status & QS_READY) == 0)
141718781Sgibbs		next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD);
141818781Sgibbs
141918781Sgibbs	return (next_qp);
142018781Sgibbs}
142118781Sgibbs
142218781Sgibbsstatic int
142318781Sgibbsadv_send_scsi_queue(adv, scsiq, n_q_required)
142418781Sgibbs	struct adv_softc *adv;
142518781Sgibbs	struct adv_scsi_q *scsiq;
142618781Sgibbs	u_int8_t n_q_required;
142718781Sgibbs{
142818781Sgibbs	u_int8_t	free_q_head;
142918781Sgibbs	u_int8_t	next_qp;
143018781Sgibbs	u_int8_t	tid_no;
143118781Sgibbs	u_int8_t	target_ix;
143218781Sgibbs	int		retval;
143318781Sgibbs
143418781Sgibbs	retval = 1;
143518781Sgibbs	target_ix = scsiq->q2.target_ix;
143618781Sgibbs	tid_no = ADV_TIX_TO_TID(target_ix);
143718781Sgibbs	free_q_head = adv_read_lram_16(adv, ADVV_FREE_Q_HEAD_W) & 0xFF;
143818781Sgibbs	if ((next_qp = adv_alloc_free_queues(adv, free_q_head, n_q_required))
143918781Sgibbs	    != ADV_QLINK_END) {
144018781Sgibbs		if (n_q_required > 1) {
144118781Sgibbs			/*
144218781Sgibbs			 * Only reset the shortage value when processing
144318781Sgibbs			 * a "normal" request and not error recovery or
144418781Sgibbs			 * other requests that dip into our reserved queues.
144518781Sgibbs			 * Generally speaking, a normal request will need more
144618781Sgibbs			 * than one queue.
144718781Sgibbs			 */
144818781Sgibbs			adv->openings_needed = 0;
144918781Sgibbs		}
145018781Sgibbs		scsiq->q1.q_no = free_q_head;
145118781Sgibbs
145218781Sgibbs		/*
145318781Sgibbs		 * Now that we know our Q number, point our sense
145418781Sgibbs		 * buffer pointer to an area below 16M if we are
145518781Sgibbs		 * an ISA adapter.
145618781Sgibbs		 */
145718781Sgibbs		if (adv->sense_buffers != NULL)
145818781Sgibbs			scsiq->q1.sense_addr = (u_int32_t)vtophys(&(adv->sense_buffers[free_q_head]));
145918781Sgibbs		adv_put_ready_sg_list_queue(adv, scsiq, free_q_head);
146018781Sgibbs		adv_write_lram_16(adv, ADVV_FREE_Q_HEAD_W, next_qp);
146118781Sgibbs		adv->cur_active += n_q_required;
146218781Sgibbs		retval = 0;
146318781Sgibbs	}
146418781Sgibbs	return (retval);
146518781Sgibbs}
146618781Sgibbs
146718781Sgibbs
146818781Sgibbsstatic void
146918781Sgibbsadv_put_ready_sg_list_queue(adv, scsiq, q_no)
147018781Sgibbs	struct	adv_softc *adv;
147118781Sgibbs	struct 	adv_scsi_q *scsiq;
147218781Sgibbs	u_int8_t q_no;
147318781Sgibbs{
147418781Sgibbs	u_int8_t	sg_list_dwords;
147518781Sgibbs	u_int8_t	sg_index, i;
147618781Sgibbs	u_int8_t	sg_entry_cnt;
147718781Sgibbs	u_int8_t	next_qp;
147818781Sgibbs	u_int16_t	q_addr;
147918781Sgibbs	struct		adv_sg_head *sg_head;
148018781Sgibbs	struct		adv_sg_list_q scsi_sg_q;
148118781Sgibbs
148218781Sgibbs	sg_head = scsiq->sg_head;
148318781Sgibbs
148418781Sgibbs	if (sg_head) {
148518781Sgibbs		sg_entry_cnt = sg_head->entry_cnt - 1;
148618781Sgibbs#ifdef DIAGNOSTIC
148718781Sgibbs		if (sg_entry_cnt == 0)
148818781Sgibbs			panic("adv_put_ready_sg_list_queue: ScsiQ with a SG list but only one element");
148918781Sgibbs		if ((scsiq->q1.cntl & QC_SG_HEAD) == 0)
149018781Sgibbs			panic("adv_put_ready_sg_list_queue: ScsiQ with a SG list but QC_SG_HEAD not set");
149118781Sgibbs#endif
149218781Sgibbs		q_addr = ADV_QNO_TO_QADDR(q_no);
149318781Sgibbs		sg_index = 1;
149418781Sgibbs		scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
149518781Sgibbs		scsi_sg_q.sg_head_qp = q_no;
149618781Sgibbs		scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
149718781Sgibbs		for (i = 0; i < sg_head->queue_cnt; i++) {
149818781Sgibbs			u_int8_t segs_this_q;
149918781Sgibbs
150018781Sgibbs			if (sg_entry_cnt > ADV_SG_LIST_PER_Q)
150118781Sgibbs				segs_this_q = ADV_SG_LIST_PER_Q;
150218781Sgibbs			else {
150318781Sgibbs				/* This will be the last segment then */
150418781Sgibbs				segs_this_q = sg_entry_cnt;
150518781Sgibbs				scsi_sg_q.cntl |= QCSG_SG_XFER_END;
150618781Sgibbs			}
150718781Sgibbs			scsi_sg_q.seq_no = i + 1;
150818781Sgibbs			sg_list_dwords = segs_this_q * 2;
150918781Sgibbs			if (i == 0) {
151018781Sgibbs				scsi_sg_q.sg_list_cnt = segs_this_q;
151118781Sgibbs				scsi_sg_q.sg_cur_list_cnt = segs_this_q;
151218781Sgibbs			} else {
151318781Sgibbs				scsi_sg_q.sg_list_cnt = segs_this_q - 1;
151418781Sgibbs				scsi_sg_q.sg_cur_list_cnt = segs_this_q - 1;
151518781Sgibbs			}
151618781Sgibbs			next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD);
151718781Sgibbs			scsi_sg_q.q_no = next_qp;
151818781Sgibbs			q_addr = ADV_QNO_TO_QADDR(next_qp);
151918781Sgibbs
152018781Sgibbs			adv_write_lram_16_multi(adv, q_addr + ADV_SCSIQ_SGHD_CPY_BEG,
152118781Sgibbs						(u_int16_t *)&scsi_sg_q,
152218781Sgibbs						sizeof(scsi_sg_q) >> 1);
152318781Sgibbs			adv_write_lram_32_multi(adv, q_addr + ADV_SGQ_LIST_BEG,
152418781Sgibbs						(u_int32_t *)&sg_head->sg_list[sg_index],
152518781Sgibbs						sg_list_dwords);
152618781Sgibbs			sg_entry_cnt -= segs_this_q;
152718781Sgibbs			sg_index += ADV_SG_LIST_PER_Q;
152818781Sgibbs		}
152918781Sgibbs	}
153018781Sgibbs	adv_put_ready_queue(adv, scsiq, q_no);
153118781Sgibbs}
153218781Sgibbs
153318781Sgibbsstatic void
153418781Sgibbsadv_put_ready_queue(adv, scsiq, q_no)
153518781Sgibbs	struct adv_softc *adv;
153618781Sgibbs	struct adv_scsi_q *scsiq;
153718781Sgibbs	u_int8_t q_no;
153818781Sgibbs{
153918781Sgibbs	u_int16_t	q_addr;
154018781Sgibbs	u_int8_t	tid_no;
154118781Sgibbs	u_int8_t	sdtr_data;
154218781Sgibbs	u_int8_t	syn_period_ix;
154318781Sgibbs	u_int8_t	syn_offset;
154418781Sgibbs
154518781Sgibbs	if (((adv->initiate_sdtr & scsiq->q1.target_id) != 0) &&
154618781Sgibbs	    ((adv->sdtr_done & scsiq->q1.target_id) == 0)) {
154718781Sgibbs
154818781Sgibbs		tid_no = ADV_TIX_TO_TID(scsiq->q2.target_ix);
154918781Sgibbs
155018781Sgibbs		sdtr_data = adv_read_lram_8(adv, ADVV_SDTR_DATA_BEG + tid_no);
155118781Sgibbs		syn_period_ix = (sdtr_data >> 4) & (ADV_SYN_XFER_NO - 1);
155218781Sgibbs		syn_offset = sdtr_data & ADV_SYN_MAX_OFFSET;
155318781Sgibbs		adv_msgout_sdtr(adv, adv_sdtr_period_tbl[syn_period_ix],
155418781Sgibbs				 syn_offset);
155518781Sgibbs
155618781Sgibbs		scsiq->q1.cntl |= QC_MSG_OUT;
155718781Sgibbs	}
155818781Sgibbs	q_addr = ADV_QNO_TO_QADDR(q_no);
155918781Sgibbs
156018781Sgibbs	scsiq->q1.status = QS_FREE;
156118781Sgibbs
156218781Sgibbs	adv_write_lram_16_multi(adv, q_addr + ADV_SCSIQ_CDB_BEG,
156318781Sgibbs				(u_int16_t *)scsiq->cdbptr,
156418781Sgibbs				scsiq->q2.cdb_len >> 1);
156518781Sgibbs
156618781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
156718781Sgibbs	adv_adj_scsiq_endian(scsiq);
156818781Sgibbs#endif
156918781Sgibbs
157018781Sgibbs	adv_put_scsiq(adv, q_addr + ADV_SCSIQ_CPY_BEG,
157118781Sgibbs		      (u_int16_t *) &scsiq->q1.cntl,
157218781Sgibbs		      ((sizeof(scsiq->q1) + sizeof(scsiq->q2)) / 2) - 1);
157318781Sgibbs
157418781Sgibbs#if CC_WRITE_IO_COUNT
157518781Sgibbs	adv_write_lram_16(adv, q_addr + ADV_SCSIQ_W_REQ_COUNT,
157618781Sgibbs			  adv->req_count);
157718781Sgibbs#endif
157818781Sgibbs
157918781Sgibbs#if CC_CLEAR_DMA_REMAIN
158018781Sgibbs
158118781Sgibbs	adv_write_lram_32(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_ADDR, 0);
158218781Sgibbs	adv_write_lram_32(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_CNT, 0);
158318781Sgibbs#endif
158418781Sgibbs
158518781Sgibbs	adv_write_lram_16(adv, q_addr + ADV_SCSIQ_B_STATUS,
158618781Sgibbs			  (scsiq->q1.q_no << 8) | QS_READY);
158718781Sgibbs}
158818781Sgibbs
158918781Sgibbsstatic void
159018781Sgibbsadv_put_scsiq(adv, s_addr, buffer, words)
159118781Sgibbs	struct adv_softc *adv;
159218781Sgibbs	u_int16_t s_addr;
159318781Sgibbs	u_int16_t *buffer;
159418781Sgibbs	int words;
159518781Sgibbs{
159618781Sgibbs	int	i;
159718781Sgibbs
159818781Sgibbs	/*
159918781Sgibbs	 * XXX This routine makes *gross* assumptions
160018781Sgibbs	 * about padding in the data structures.
160118781Sgibbs	 * Either the data structures should have explicit
160218781Sgibbs	 * padding members added, or they should have padding
160318781Sgibbs	 * turned off via compiler attributes depending on
160418781Sgibbs	 * which yields better overall performance.  My hunch
160518781Sgibbs	 * would be that turning off padding would be the
160618781Sgibbs	 * faster approach as an outsw is much faster than
160718781Sgibbs	 * this crude loop and accessing un-aligned data
160818781Sgibbs	 * members isn't *that* expensive.  The other choice
160918781Sgibbs	 * would be to modify the ASC script so that the
161018781Sgibbs	 * the adv_scsiq_1 structure can be re-arranged so
161118781Sgibbs	 * padding isn't required.
161218781Sgibbs	 */
161318781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
161418781Sgibbs	for (i = 0; i < words; i++, buffer++) {
161518781Sgibbs		if (i == 2 || i == 10) {
161618781Sgibbs			continue;
161718781Sgibbs		}
161818781Sgibbs		ADV_OUTW(adv, ADV_LRAM_DATA, *buffer);
161918781Sgibbs	}
162018781Sgibbs}
162118781Sgibbs
162218781Sgibbsstatic u_int8_t
162318781Sgibbsadv_msgout_sdtr(adv, sdtr_period, sdtr_offset)
162418781Sgibbs	struct adv_softc *adv;
162518781Sgibbs	u_int8_t sdtr_period;
162618781Sgibbs	u_int8_t sdtr_offset;
162718781Sgibbs{
162818781Sgibbs	struct	 sdtr_xmsg sdtr_buf;
162918781Sgibbs
163018781Sgibbs	sdtr_buf.msg_type = MSG_EXTENDED;
163118781Sgibbs	sdtr_buf.msg_len = MSG_EXT_SDTR_LEN;
163218781Sgibbs	sdtr_buf.msg_req = MSG_EXT_SDTR;
163318781Sgibbs	sdtr_buf.xfer_period = sdtr_period;
163418781Sgibbs	sdtr_offset &= ADV_SYN_MAX_OFFSET;
163518781Sgibbs	sdtr_buf.req_ack_offset = sdtr_offset;
163618781Sgibbs	adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG,
163718781Sgibbs				(u_int16_t *) &sdtr_buf,
163818781Sgibbs				sizeof(sdtr_buf) / 2);
163918781Sgibbs
164018781Sgibbs	return (adv_get_card_sync_setting(sdtr_period, sdtr_offset));
164118781Sgibbs}
164218781Sgibbs
164318781Sgibbsstatic u_int8_t
164418781Sgibbsadv_get_card_sync_setting(period, offset)
164518781Sgibbs	u_int8_t period;
164618781Sgibbs	u_int8_t offset;
164718781Sgibbs{
164818781Sgibbs	u_int i;
164918781Sgibbs
165018781Sgibbs	if (period >= adv_sdtr_period_tbl[0]) {
165118781Sgibbs		for (i = 0; i < sizeof(adv_sdtr_period_tbl); i++) {
165218781Sgibbs			if (period <= adv_sdtr_period_tbl[i])
165318781Sgibbs				return ((adv_sdtr_period_tbl[i] << 4) | offset);
165418781Sgibbs		}
165518781Sgibbs	}
165618781Sgibbs	return (0);
165718781Sgibbs}
165818781Sgibbs
165918781Sgibbsstatic void
166018781Sgibbsadv_set_chip_sdtr(adv, sdtr_data, tid_no)
166118781Sgibbs	struct adv_softc *adv;
166218781Sgibbs	u_int8_t sdtr_data;
166318781Sgibbs	u_int8_t tid_no;
166418781Sgibbs{
166518781Sgibbs	ADV_OUTB(adv, ADV_SYN_OFFSET, sdtr_data);
166618781Sgibbs	adv_write_lram_8(adv, ADVV_SDTR_DONE_BEG + tid_no, sdtr_data);
166718781Sgibbs}
1668