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$");
46119418Sobrien
4718781Sgibbs#include <sys/param.h>
48241492Sjhb#include <sys/conf.h>
49241492Sjhb#include <sys/lock.h>
5045846Sgibbs#include <sys/kernel.h>
51241492Sjhb#include <sys/mutex.h>
5218781Sgibbs#include <sys/systm.h>
5318781Sgibbs
5439217Sgibbs#include <machine/bus.h>
5559082Snyan#include <machine/resource.h>
5659082Snyan#include <sys/bus.h>
5759082Snyan#include <sys/rman.h>
5818781Sgibbs
5939217Sgibbs#include <cam/cam.h>
6039217Sgibbs#include <cam/cam_ccb.h>
6139217Sgibbs#include <cam/cam_sim.h>
6239217Sgibbs#include <cam/cam_xpt_sim.h>
6318781Sgibbs
6439217Sgibbs#include <cam/scsi/scsi_all.h>
6539217Sgibbs#include <cam/scsi/scsi_message.h>
6639217Sgibbs#include <cam/scsi/scsi_da.h>
6739217Sgibbs#include <cam/scsi/scsi_cd.h>
6839217Sgibbs
6918781Sgibbs#include <vm/vm.h>
7018781Sgibbs#include <vm/vm_param.h>
7118781Sgibbs#include <vm/pmap.h>
7218781Sgibbs
7339217Sgibbs#include <dev/advansys/advansys.h>
7418781Sgibbs#include <dev/advansys/advmcode.h>
7518781Sgibbs
7639217Sgibbsstruct adv_quirk_entry {
7739217Sgibbs	struct scsi_inquiry_pattern inq_pat;
7839217Sgibbs	u_int8_t quirks;
7939217Sgibbs#define ADV_QUIRK_FIX_ASYN_XFER_ALWAYS	0x01
8039217Sgibbs#define ADV_QUIRK_FIX_ASYN_XFER		0x02
8139217Sgibbs};
8239217Sgibbs
8339217Sgibbsstatic struct adv_quirk_entry adv_quirk_table[] =
8439217Sgibbs{
8539217Sgibbs	{
8639217Sgibbs		{ T_CDROM, SIP_MEDIA_REMOVABLE, "HP", "*", "*" },
8739217Sgibbs		ADV_QUIRK_FIX_ASYN_XFER_ALWAYS|ADV_QUIRK_FIX_ASYN_XFER
8839217Sgibbs	},
8939217Sgibbs	{
9039217Sgibbs		{ T_CDROM, SIP_MEDIA_REMOVABLE, "NEC", "CD-ROM DRIVE", "*" },
9139217Sgibbs		0
9239217Sgibbs	},
9339217Sgibbs	{
9439217Sgibbs		{
9539217Sgibbs		  T_SEQUENTIAL, SIP_MEDIA_REMOVABLE,
9639217Sgibbs		  "TANDBERG", " TDC 36", "*"
9739217Sgibbs		},
9839217Sgibbs		0
9939217Sgibbs	},
10039217Sgibbs	{
10139217Sgibbs		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "WANGTEK", "*", "*" },
10239217Sgibbs		0
10339217Sgibbs	},
10439217Sgibbs	{
10539217Sgibbs		{
10639217Sgibbs		  T_PROCESSOR, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
10739217Sgibbs		  "*", "*", "*"
10839217Sgibbs		},
10939217Sgibbs		0
11039217Sgibbs	},
11139217Sgibbs	{
11239217Sgibbs		{
11339217Sgibbs		  T_SCANNER, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
11439217Sgibbs		  "*", "*", "*"
11539217Sgibbs		},
11639217Sgibbs		0
11739217Sgibbs	},
11839217Sgibbs	{
11939217Sgibbs		/* Default quirk entry */
12039217Sgibbs		{
12139217Sgibbs		  T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
12239217Sgibbs		  /*vendor*/"*", /*product*/"*", /*revision*/"*"
12339217Sgibbs                },
12439217Sgibbs                ADV_QUIRK_FIX_ASYN_XFER,
12539217Sgibbs	}
12639217Sgibbs};
12739217Sgibbs
12818781Sgibbs/*
12918781Sgibbs * Allowable periods in ns
13018781Sgibbs */
13145575Seivindstatic u_int8_t adv_sdtr_period_tbl[] =
13218781Sgibbs{
13318781Sgibbs	25,
13418781Sgibbs	30,
13518781Sgibbs	35,
13618781Sgibbs	40,
13718781Sgibbs	50,
13818781Sgibbs	60,
13918781Sgibbs	70,
14018781Sgibbs	85
14118781Sgibbs};
14218781Sgibbs
14345575Seivindstatic u_int8_t adv_sdtr_period_tbl_ultra[] =
14439217Sgibbs{
14539217Sgibbs	12,
14639217Sgibbs	19,
14739217Sgibbs	25,
14839217Sgibbs	32,
14939217Sgibbs	38,
15039217Sgibbs	44,
15139217Sgibbs	50,
15239217Sgibbs	57,
15339217Sgibbs	63,
15439217Sgibbs	69,
15539217Sgibbs	75,
15639217Sgibbs	82,
15739217Sgibbs	88,
15839217Sgibbs	94,
15939217Sgibbs	100,
16039217Sgibbs	107
16118781Sgibbs};
16218781Sgibbs
16339217Sgibbsstruct ext_msg {
16439217Sgibbs	u_int8_t msg_type;
16539217Sgibbs	u_int8_t msg_len;
16639217Sgibbs	u_int8_t msg_req;
16739217Sgibbs	union {
16839217Sgibbs		struct {
16939217Sgibbs			u_int8_t sdtr_xfer_period;
17039217Sgibbs			u_int8_t sdtr_req_ack_offset;
17139217Sgibbs		} sdtr;
17239217Sgibbs		struct {
17339217Sgibbs       			u_int8_t wdtr_width;
17439217Sgibbs		} wdtr;
17539217Sgibbs		struct {
17639217Sgibbs			u_int8_t mdp[4];
17739217Sgibbs		} mdp;
17839217Sgibbs	} u_ext_msg;
17939217Sgibbs	u_int8_t res;
18039217Sgibbs};
18139217Sgibbs
18239217Sgibbs#define	xfer_period	u_ext_msg.sdtr.sdtr_xfer_period
18339217Sgibbs#define	req_ack_offset	u_ext_msg.sdtr.sdtr_req_ack_offset
18439217Sgibbs#define	wdtr_width	u_ext_msg.wdtr.wdtr_width
18539217Sgibbs#define	mdp_b3		u_ext_msg.mdp_b3
18639217Sgibbs#define	mdp_b2		u_ext_msg.mdp_b2
18739217Sgibbs#define	mdp_b1		u_ext_msg.mdp_b1
18839217Sgibbs#define	mdp_b0		u_ext_msg.mdp_b0
18939217Sgibbs
19018781Sgibbs/*
19118781Sgibbs * Some of the early PCI adapters have problems with
19239217Sgibbs * async transfers.  Instead use an offset of 1.
19318781Sgibbs */
19439217Sgibbs#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
19518781Sgibbs
19618781Sgibbs/* LRAM routines */
19739217Sgibbsstatic void	 adv_read_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr,
19839217Sgibbs					u_int16_t *buffer, int count);
19939217Sgibbsstatic void	 adv_write_lram_16_multi(struct adv_softc *adv,
20039217Sgibbs					 u_int16_t s_addr, u_int16_t *buffer,
20139217Sgibbs					 int count);
20239217Sgibbsstatic void	 adv_mset_lram_16(struct adv_softc *adv, u_int16_t s_addr,
20339217Sgibbs				  u_int16_t set_value, int count);
20439217Sgibbsstatic u_int32_t adv_msum_lram_16(struct adv_softc *adv, u_int16_t s_addr,
20539217Sgibbs				  int count);
20618781Sgibbs
20739217Sgibbsstatic int	 adv_write_and_verify_lram_16(struct adv_softc *adv,
20839217Sgibbs					      u_int16_t addr, u_int16_t value);
20939217Sgibbsstatic u_int32_t adv_read_lram_32(struct adv_softc *adv, u_int16_t addr);
21018781Sgibbs
21118781Sgibbs
21239217Sgibbsstatic void	 adv_write_lram_32(struct adv_softc *adv, u_int16_t addr,
21339217Sgibbs				   u_int32_t value);
21439217Sgibbsstatic void	 adv_write_lram_32_multi(struct adv_softc *adv,
21539217Sgibbs					 u_int16_t s_addr, u_int32_t *buffer,
21639217Sgibbs					 int count);
21718781Sgibbs
21818781Sgibbs/* EEPROM routines */
21939217Sgibbsstatic u_int16_t adv_read_eeprom_16(struct adv_softc *adv, u_int8_t addr);
22039217Sgibbsstatic u_int16_t adv_write_eeprom_16(struct adv_softc *adv, u_int8_t addr,
22139217Sgibbs				     u_int16_t value);
22239217Sgibbsstatic int	 adv_write_eeprom_cmd_reg(struct adv_softc *adv,
22339217Sgibbs					  u_int8_t cmd_reg);
22439217Sgibbsstatic int	 adv_set_eeprom_config_once(struct adv_softc *adv,
22539217Sgibbs					    struct adv_eeprom_config *eeconfig);
22618781Sgibbs
22718781Sgibbs/* Initialization */
22839217Sgibbsstatic u_int32_t adv_load_microcode(struct adv_softc *adv, u_int16_t s_addr,
22939217Sgibbs				    u_int16_t *mcode_buf, u_int16_t mcode_size);
23018781Sgibbs
23139217Sgibbsstatic void	 adv_reinit_lram(struct adv_softc *adv);
23239217Sgibbsstatic void	 adv_init_lram(struct adv_softc *adv);
23339217Sgibbsstatic int	 adv_init_microcode_var(struct adv_softc *adv);
23439217Sgibbsstatic void	 adv_init_qlink_var(struct adv_softc *adv);
23539217Sgibbs
23618781Sgibbs/* Interrupts */
23739217Sgibbsstatic void	 adv_disable_interrupt(struct adv_softc *adv);
23839217Sgibbsstatic void	 adv_enable_interrupt(struct adv_softc *adv);
23939217Sgibbsstatic void	 adv_toggle_irq_act(struct adv_softc *adv);
24018781Sgibbs
24118781Sgibbs/* Chip Control */
24239217Sgibbsstatic int	 adv_host_req_chip_halt(struct adv_softc *adv);
24339217Sgibbsstatic void	 adv_set_chip_ih(struct adv_softc *adv, u_int16_t ins_code);
244153072Sru#if 0
24539217Sgibbsstatic u_int8_t  adv_get_chip_scsi_ctrl(struct adv_softc *adv);
24618781Sgibbs#endif
24718781Sgibbs
24818781Sgibbs/* Queue handling and execution */
24940027Sgibbsstatic __inline int
25040027Sgibbs		 adv_sgcount_to_qcount(int sgcount);
25140027Sgibbs
25240027Sgibbsstatic __inline int
25340027Sgibbsadv_sgcount_to_qcount(int sgcount)
25440027Sgibbs{
25540027Sgibbs	int	n_sg_list_qs;
25640027Sgibbs
25740027Sgibbs	n_sg_list_qs = ((sgcount - 1) / ADV_SG_LIST_PER_Q);
25840027Sgibbs	if (((sgcount - 1) % ADV_SG_LIST_PER_Q) != 0)
25940027Sgibbs		n_sg_list_qs++;
26040027Sgibbs	return (n_sg_list_qs + 1);
26140027Sgibbs}
26240027Sgibbs
263111409Sobrien#if BYTE_ORDER == BIG_ENDIAN
264111342Sobrienstatic void	 adv_adj_endian_qdone_info(struct adv_q_done_info *);
265111342Sobrienstatic void	 adv_adj_scsiq_endian(struct adv_scsi_q *);
266111409Sobrien#endif
26739217Sgibbsstatic void	 adv_get_q_info(struct adv_softc *adv, u_int16_t s_addr,
26839217Sgibbs				u_int16_t *inbuf, int words);
26939217Sgibbsstatic u_int	 adv_get_num_free_queues(struct adv_softc *adv, u_int8_t n_qs);
27039217Sgibbsstatic u_int8_t  adv_alloc_free_queues(struct adv_softc *adv,
27139217Sgibbs				       u_int8_t free_q_head, u_int8_t n_free_q);
27239217Sgibbsstatic u_int8_t  adv_alloc_free_queue(struct adv_softc *adv,
27339217Sgibbs				      u_int8_t free_q_head);
27439217Sgibbsstatic int	 adv_send_scsi_queue(struct adv_softc *adv,
27539217Sgibbs				     struct adv_scsi_q *scsiq,
27639217Sgibbs				     u_int8_t n_q_required);
27739217Sgibbsstatic void	 adv_put_ready_sg_list_queue(struct adv_softc *adv,
27839217Sgibbs					     struct adv_scsi_q *scsiq,
27939217Sgibbs					     u_int q_no);
28039217Sgibbsstatic void	 adv_put_ready_queue(struct adv_softc *adv,
28139217Sgibbs				     struct adv_scsi_q *scsiq, u_int q_no);
28239217Sgibbsstatic void	 adv_put_scsiq(struct adv_softc *adv, u_int16_t s_addr,
28339217Sgibbs			       u_int16_t *buffer, int words);
28418781Sgibbs
28539217Sgibbs/* Messages */
28639217Sgibbsstatic void	 adv_handle_extmsg_in(struct adv_softc *adv,
28739217Sgibbs				      u_int16_t halt_q_addr, u_int8_t q_cntl,
28839217Sgibbs				      target_bit_vector target_id,
28939217Sgibbs				      int tid);
29039217Sgibbsstatic void	 adv_msgout_sdtr(struct adv_softc *adv, u_int8_t sdtr_period,
29139217Sgibbs				 u_int8_t sdtr_offset);
29239217Sgibbsstatic void	 adv_set_sdtr_reg_at_id(struct adv_softc *adv, int id,
29339217Sgibbs					u_int8_t sdtr_data);
29418781Sgibbs
29518781Sgibbs
29619426Sgibbs/* Exported functions first */
29718781Sgibbs
29839217Sgibbsvoid
29939217Sgibbsadvasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
30039217Sgibbs{
30118781Sgibbs	struct adv_softc *adv;
30239217Sgibbs
30339217Sgibbs	adv = (struct adv_softc *)callback_arg;
304241492Sjhb	mtx_assert(&adv->lock, MA_OWNED);
30539217Sgibbs	switch (code) {
30639217Sgibbs	case AC_FOUND_DEVICE:
30739217Sgibbs	{
30839217Sgibbs		struct ccb_getdev *cgd;
30939217Sgibbs		target_bit_vector target_mask;
31039217Sgibbs		int num_entries;
31139217Sgibbs        	caddr_t match;
31239217Sgibbs		struct adv_quirk_entry *entry;
31339217Sgibbs		struct adv_target_transinfo* tinfo;
31439217Sgibbs
31539217Sgibbs		cgd = (struct ccb_getdev *)arg;
31639217Sgibbs
31739217Sgibbs		target_mask = ADV_TID_TO_TARGET_MASK(cgd->ccb_h.target_id);
31839217Sgibbs
319298431Spfg		num_entries = nitems(adv_quirk_table);
32039217Sgibbs		match = cam_quirkmatch((caddr_t)&cgd->inq_data,
32139217Sgibbs				       (caddr_t)adv_quirk_table,
32239217Sgibbs				       num_entries, sizeof(*adv_quirk_table),
32339217Sgibbs				       scsi_inquiry_match);
32439217Sgibbs
32539217Sgibbs		if (match == NULL)
32639217Sgibbs			panic("advasync: device didn't match wildcard entry!!");
32739217Sgibbs
32839217Sgibbs		entry = (struct adv_quirk_entry *)match;
32939217Sgibbs
33039217Sgibbs		if (adv->bug_fix_control & ADV_BUG_FIX_ASYN_USE_SYN) {
33139217Sgibbs			if ((entry->quirks & ADV_QUIRK_FIX_ASYN_XFER_ALWAYS)!=0)
33239217Sgibbs				adv->fix_asyn_xfer_always |= target_mask;
33339217Sgibbs			else
33439217Sgibbs				adv->fix_asyn_xfer_always &= ~target_mask;
33539217Sgibbs			/*
33639217Sgibbs			 * We start out life with all bits set and clear them
33739217Sgibbs			 * after we've determined that the fix isn't necessary.
33839217Sgibbs			 * It may well be that we've already cleared a target
33939217Sgibbs			 * before the full inquiry session completes, so don't
34039217Sgibbs			 * gratuitously set a target bit even if it has this
34139217Sgibbs			 * quirk.  But, if the quirk exonerates a device, clear
34239217Sgibbs			 * the bit now.
34339217Sgibbs			 */
34439217Sgibbs			if ((entry->quirks & ADV_QUIRK_FIX_ASYN_XFER) == 0)
34539217Sgibbs				adv->fix_asyn_xfer &= ~target_mask;
34639217Sgibbs		}
34739217Sgibbs		/*
34839217Sgibbs		 * Reset our sync settings now that we've determined
34939217Sgibbs		 * what quirks are in effect for the device.
35039217Sgibbs		 */
35139217Sgibbs		tinfo = &adv->tinfo[cgd->ccb_h.target_id];
35239217Sgibbs		adv_set_syncrate(adv, cgd->ccb_h.path,
35339217Sgibbs				 cgd->ccb_h.target_id,
35439217Sgibbs				 tinfo->current.period,
35539217Sgibbs				 tinfo->current.offset,
35639217Sgibbs				 ADV_TRANS_CUR);
35739217Sgibbs		break;
35839217Sgibbs	}
35939217Sgibbs	case AC_LOST_DEVICE:
36039217Sgibbs	{
36139217Sgibbs		u_int target_mask;
36239217Sgibbs
36339217Sgibbs		if (adv->bug_fix_control & ADV_BUG_FIX_ASYN_USE_SYN) {
36439217Sgibbs			target_mask = 0x01 << xpt_path_target_id(path);
36539217Sgibbs			adv->fix_asyn_xfer |= target_mask;
36639217Sgibbs		}
36739217Sgibbs
36839217Sgibbs		/*
36939217Sgibbs		 * Revert to async transfers
37039217Sgibbs		 * for the next device.
37139217Sgibbs		 */
37239217Sgibbs		adv_set_syncrate(adv, /*path*/NULL,
37339217Sgibbs				 xpt_path_target_id(path),
37439217Sgibbs				 /*period*/0,
37539217Sgibbs				 /*offset*/0,
37639217Sgibbs				 ADV_TRANS_GOAL|ADV_TRANS_CUR);
37739217Sgibbs	}
37839217Sgibbs	default:
37939217Sgibbs		break;
38039217Sgibbs	}
38139217Sgibbs}
38239217Sgibbs
38339217Sgibbsvoid
38439217Sgibbsadv_set_bank(struct adv_softc *adv, u_int8_t bank)
38518781Sgibbs{
38639217Sgibbs	u_int8_t control;
38739217Sgibbs
38839217Sgibbs	/*
38939217Sgibbs	 * Start out with the bank reset to 0
39039217Sgibbs	 */
39139217Sgibbs	control = ADV_INB(adv, ADV_CHIP_CTRL)
39239217Sgibbs		  &  (~(ADV_CC_SINGLE_STEP | ADV_CC_TEST
39339217Sgibbs			| ADV_CC_DIAG | ADV_CC_SCSI_RESET
39439217Sgibbs			| ADV_CC_CHIP_RESET | ADV_CC_BANK_ONE));
39539217Sgibbs	if (bank == 1) {
39639217Sgibbs		control |= ADV_CC_BANK_ONE;
39739217Sgibbs	} else if (bank == 2) {
39839217Sgibbs		control |= ADV_CC_DIAG | ADV_CC_BANK_ONE;
39939217Sgibbs	}
40039217Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, control);
40139217Sgibbs}
40239217Sgibbs
40339217Sgibbsu_int8_t
40439217Sgibbsadv_read_lram_8(struct adv_softc *adv, u_int16_t addr)
40539217Sgibbs{
40618781Sgibbs	u_int8_t   byte_data;
40718781Sgibbs	u_int16_t  word_data;
40818781Sgibbs
40918781Sgibbs	/*
41018781Sgibbs	 * LRAM is accessed on 16bit boundaries.
41118781Sgibbs	 */
41218781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr & 0xFFFE);
41318781Sgibbs	word_data = ADV_INW(adv, ADV_LRAM_DATA);
41418781Sgibbs	if (addr & 1) {
41518781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
41618781Sgibbs		byte_data = (u_int8_t)(word_data & 0xFF);
41718781Sgibbs#else
41818781Sgibbs		byte_data = (u_int8_t)((word_data >> 8) & 0xFF);
41918781Sgibbs#endif
42018781Sgibbs	} else {
42118781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
42218781Sgibbs		byte_data = (u_int8_t)((word_data >> 8) & 0xFF);
42318781Sgibbs#else
42418781Sgibbs		byte_data = (u_int8_t)(word_data & 0xFF);
42518781Sgibbs#endif
42618781Sgibbs	}
42718781Sgibbs	return (byte_data);
42818781Sgibbs}
42918781Sgibbs
43018781Sgibbsvoid
43139217Sgibbsadv_write_lram_8(struct adv_softc *adv, u_int16_t addr, u_int8_t value)
43218781Sgibbs{
43318781Sgibbs	u_int16_t word_data;
43418781Sgibbs
43518781Sgibbs	word_data = adv_read_lram_16(adv, addr & 0xFFFE);
43618781Sgibbs	if (addr & 1) {
43718781Sgibbs		word_data &= 0x00FF;
43818781Sgibbs		word_data |= (((u_int8_t)value << 8) & 0xFF00);
43918781Sgibbs	} else {
44018781Sgibbs		word_data &= 0xFF00;
44118781Sgibbs		word_data |= ((u_int8_t)value & 0x00FF);
44218781Sgibbs	}
44318781Sgibbs	adv_write_lram_16(adv, addr & 0xFFFE, word_data);
44418781Sgibbs}
44518781Sgibbs
44618781Sgibbs
44718781Sgibbsu_int16_t
44839217Sgibbsadv_read_lram_16(struct adv_softc *adv, u_int16_t addr)
44918781Sgibbs{
45018781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
45118781Sgibbs	return (ADV_INW(adv, ADV_LRAM_DATA));
45218781Sgibbs}
45318781Sgibbs
45418781Sgibbsvoid
45539217Sgibbsadv_write_lram_16(struct adv_softc *adv, u_int16_t addr, u_int16_t value)
45618781Sgibbs{
45718781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
45818781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, value);
45918781Sgibbs}
46018781Sgibbs
46118781Sgibbs/*
46239217Sgibbs * Determine if there is a board at "iobase" by looking
46339217Sgibbs * for the AdvanSys signatures.  Return 1 if a board is
46439217Sgibbs * found, 0 otherwise.
46518781Sgibbs */
46639217Sgibbsint
467241492Sjhbadv_find_signature(struct resource *res)
46839217Sgibbs{
46939217Sgibbs	u_int16_t signature;
47039217Sgibbs
471241492Sjhb	if (bus_read_1(res, ADV_SIGNATURE_BYTE) == ADV_1000_ID1B) {
472241492Sjhb		signature = bus_read_2(res, ADV_SIGNATURE_WORD);
47339217Sgibbs		if ((signature == ADV_1000_ID0W)
47439217Sgibbs		 || (signature == ADV_1000_ID0W_FIX))
47539217Sgibbs			return (1);
47639217Sgibbs	}
47739217Sgibbs	return (0);
47839217Sgibbs}
47939217Sgibbs
48018781Sgibbsvoid
48139217Sgibbsadv_lib_init(struct adv_softc *adv)
48218781Sgibbs{
48339217Sgibbs	if ((adv->type & ADV_ULTRA) != 0) {
48439217Sgibbs		adv->sdtr_period_tbl = adv_sdtr_period_tbl_ultra;
48539217Sgibbs		adv->sdtr_period_tbl_size = sizeof(adv_sdtr_period_tbl_ultra);
48639217Sgibbs	} else {
48739217Sgibbs		adv->sdtr_period_tbl = adv_sdtr_period_tbl;
48839217Sgibbs		adv->sdtr_period_tbl_size = sizeof(adv_sdtr_period_tbl);
48939217Sgibbs	}
49018781Sgibbs}
49118781Sgibbs
49218781Sgibbsu_int16_t
49339217Sgibbsadv_get_eeprom_config(struct adv_softc *adv, struct
49439217Sgibbs		      adv_eeprom_config  *eeprom_config)
49518781Sgibbs{
49618781Sgibbs	u_int16_t	sum;
49718781Sgibbs	u_int16_t	*wbuf;
49818781Sgibbs	u_int8_t	cfg_beg;
49918781Sgibbs	u_int8_t	cfg_end;
50018781Sgibbs	u_int8_t	s_addr;
50118781Sgibbs
50218781Sgibbs	wbuf = (u_int16_t *)eeprom_config;
50318781Sgibbs	sum = 0;
50418781Sgibbs
50518781Sgibbs	for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
50618781Sgibbs		*wbuf = adv_read_eeprom_16(adv, s_addr);
50718781Sgibbs		sum += *wbuf;
50818781Sgibbs	}
50918781Sgibbs
51018781Sgibbs	if (adv->type & ADV_VL) {
51118781Sgibbs		cfg_beg = ADV_EEPROM_CFG_BEG_VL;
51218781Sgibbs		cfg_end = ADV_EEPROM_MAX_ADDR_VL;
51318781Sgibbs	} else {
51418781Sgibbs		cfg_beg = ADV_EEPROM_CFG_BEG;
51518781Sgibbs		cfg_end = ADV_EEPROM_MAX_ADDR;
51618781Sgibbs	}
51718781Sgibbs
51818781Sgibbs	for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
51918781Sgibbs		*wbuf = adv_read_eeprom_16(adv, s_addr);
52018781Sgibbs		sum += *wbuf;
521153072Sru#ifdef ADV_DEBUG_EEPROM
52218781Sgibbs		printf("Addr 0x%x: 0x%04x\n", s_addr, *wbuf);
52318781Sgibbs#endif
52418781Sgibbs	}
52518781Sgibbs	*wbuf = adv_read_eeprom_16(adv, s_addr);
52618781Sgibbs	return (sum);
52718781Sgibbs}
52818781Sgibbs
52918781Sgibbsint
53039217Sgibbsadv_set_eeprom_config(struct adv_softc *adv,
53139217Sgibbs		      struct adv_eeprom_config *eeprom_config)
53218781Sgibbs{
53318781Sgibbs	int	retry;
53418781Sgibbs
53518781Sgibbs	retry = 0;
53618781Sgibbs	while (1) {
53718781Sgibbs		if (adv_set_eeprom_config_once(adv, eeprom_config) == 0) {
53818781Sgibbs			break;
53918781Sgibbs		}
54018781Sgibbs		if (++retry > ADV_EEPROM_MAX_RETRY) {
54118781Sgibbs			break;
54218781Sgibbs		}
54318781Sgibbs	}
54418781Sgibbs	return (retry > ADV_EEPROM_MAX_RETRY);
54518781Sgibbs}
54618781Sgibbs
54718781Sgibbsint
54855945Sgibbsadv_reset_chip(struct adv_softc *adv, int reset_bus)
54918781Sgibbs{
55018781Sgibbs	adv_stop_chip(adv);
55155945Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_CHIP_RESET | ADV_CC_HALT
55255945Sgibbs				     | (reset_bus ? ADV_CC_SCSI_RESET : 0));
55355945Sgibbs	DELAY(60);
55418781Sgibbs
55518781Sgibbs	adv_set_chip_ih(adv, ADV_INS_RFLAG_WTM);
55618781Sgibbs	adv_set_chip_ih(adv, ADV_INS_HALT);
55718781Sgibbs
55855945Sgibbs	if (reset_bus)
55955945Sgibbs		ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_CHIP_RESET | ADV_CC_HALT);
56055945Sgibbs
56118781Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT);
56255945Sgibbs	if (reset_bus)
56355945Sgibbs		DELAY(200 * 1000);
56455945Sgibbs
56555945Sgibbs	ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_CLR_SCSI_RESET_INT);
56655945Sgibbs	ADV_OUTW(adv, ADV_CHIP_STATUS, 0);
56718781Sgibbs	return (adv_is_chip_halted(adv));
56818781Sgibbs}
56918781Sgibbs
57018781Sgibbsint
57139217Sgibbsadv_test_external_lram(struct adv_softc* adv)
57218781Sgibbs{
57318781Sgibbs	u_int16_t	q_addr;
57418781Sgibbs	u_int16_t	saved_value;
57518781Sgibbs	int		success;
57618781Sgibbs
57718781Sgibbs	success = 0;
57818781Sgibbs
57918781Sgibbs	q_addr = ADV_QNO_TO_QADDR(241);
58018781Sgibbs	saved_value = adv_read_lram_16(adv, q_addr);
58118781Sgibbs	if (adv_write_and_verify_lram_16(adv, q_addr, 0x55AA) == 0) {
58218781Sgibbs		success = 1;
58318781Sgibbs		adv_write_lram_16(adv, q_addr, saved_value);
58418781Sgibbs	}
58518781Sgibbs	return (success);
58618781Sgibbs}
58718781Sgibbs
58818781Sgibbs
58918781Sgibbsint
59039217Sgibbsadv_init_lram_and_mcode(struct adv_softc *adv)
59118781Sgibbs{
59218781Sgibbs	u_int32_t	retval;
59339217Sgibbs
59418781Sgibbs	adv_disable_interrupt(adv);
59518781Sgibbs
59618781Sgibbs	adv_init_lram(adv);
59718781Sgibbs
59839217Sgibbs	retval = adv_load_microcode(adv, 0, (u_int16_t *)adv_mcode,
59939217Sgibbs				    adv_mcode_size);
60018781Sgibbs	if (retval != adv_mcode_chksum) {
601241492Sjhb		device_printf(adv->dev,
602241492Sjhb		    "Microcode download failed checksum!\n");
60318781Sgibbs		return (1);
60418781Sgibbs	}
60518781Sgibbs
60618781Sgibbs	if (adv_init_microcode_var(adv) != 0)
60718781Sgibbs		return (1);
60818781Sgibbs
60918781Sgibbs	adv_enable_interrupt(adv);
61018781Sgibbs	return (0);
61118781Sgibbs}
61218781Sgibbs
61318781Sgibbsu_int8_t
61439217Sgibbsadv_get_chip_irq(struct adv_softc *adv)
61518781Sgibbs{
61618781Sgibbs	u_int16_t	cfg_lsw;
61718781Sgibbs	u_int8_t	chip_irq;
61818781Sgibbs
61918781Sgibbs	cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW);
62018781Sgibbs
62118781Sgibbs	if ((adv->type & ADV_VL) != 0) {
62218781Sgibbs		chip_irq = (u_int8_t)(((cfg_lsw >> 2) & 0x07));
62318781Sgibbs		if ((chip_irq == 0) ||
62418781Sgibbs		    (chip_irq == 4) ||
62518781Sgibbs		    (chip_irq == 7)) {
62618781Sgibbs			return (0);
62718781Sgibbs		}
62818781Sgibbs		return (chip_irq + (ADV_MIN_IRQ_NO - 1));
62918781Sgibbs	}
63018781Sgibbs	chip_irq = (u_int8_t)(((cfg_lsw >> 2) & 0x03));
63118781Sgibbs	if (chip_irq == 3)
63218781Sgibbs		chip_irq += 2;
63318781Sgibbs	return (chip_irq + ADV_MIN_IRQ_NO);
63418781Sgibbs}
63518781Sgibbs
63618781Sgibbsu_int8_t
63739217Sgibbsadv_set_chip_irq(struct adv_softc *adv, u_int8_t irq_no)
63818781Sgibbs{
63918781Sgibbs	u_int16_t	cfg_lsw;
64018781Sgibbs
64118781Sgibbs	if ((adv->type & ADV_VL) != 0) {
64218781Sgibbs		if (irq_no != 0) {
64339217Sgibbs			if ((irq_no < ADV_MIN_IRQ_NO)
64439217Sgibbs			 || (irq_no > ADV_MAX_IRQ_NO)) {
64518781Sgibbs				irq_no = 0;
64618781Sgibbs			} else {
64718781Sgibbs				irq_no -= ADV_MIN_IRQ_NO - 1;
64818781Sgibbs			}
64918781Sgibbs		}
65018781Sgibbs		cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFE3;
65118781Sgibbs		cfg_lsw |= 0x0010;
65218781Sgibbs		ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw);
65318781Sgibbs		adv_toggle_irq_act(adv);
65418781Sgibbs
65518781Sgibbs		cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFE0;
65618781Sgibbs		cfg_lsw |= (irq_no & 0x07) << 2;
65718781Sgibbs		ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw);
65818781Sgibbs		adv_toggle_irq_act(adv);
65918781Sgibbs	} else if ((adv->type & ADV_ISA) != 0) {
66018781Sgibbs		if (irq_no == 15)
66118781Sgibbs			irq_no -= 2;
66218781Sgibbs		irq_no -= ADV_MIN_IRQ_NO;
66318781Sgibbs		cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFF3;
66418781Sgibbs		cfg_lsw |= (irq_no & 0x03) << 2;
66518781Sgibbs		ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw);
66618781Sgibbs	}
66718781Sgibbs	return (adv_get_chip_irq(adv));
66818781Sgibbs}
66918781Sgibbs
67039217Sgibbsvoid
67139217Sgibbsadv_set_chip_scsiid(struct adv_softc *adv, int new_id)
67239217Sgibbs{
67339217Sgibbs	u_int16_t cfg_lsw;
67439217Sgibbs
67539217Sgibbs	cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW);
67639217Sgibbs	if (ADV_CONFIG_SCSIID(cfg_lsw) == new_id)
67739217Sgibbs		return;
67839217Sgibbs    	cfg_lsw &= ~ADV_CFG_LSW_SCSIID;
67939217Sgibbs	cfg_lsw |= (new_id & ADV_MAX_TID) << ADV_CFG_LSW_SCSIID_SHIFT;
68039217Sgibbs	ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw);
68139217Sgibbs}
68239217Sgibbs
68318781Sgibbsint
68439217Sgibbsadv_execute_scsi_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq,
68539217Sgibbs		       u_int32_t datalen)
68618781Sgibbs{
68739217Sgibbs	struct		adv_target_transinfo* tinfo;
68839217Sgibbs	u_int32_t	*p_data_addr;
68939217Sgibbs	u_int32_t	*p_data_bcount;
69039217Sgibbs	int		disable_syn_offset_one_fix;
69118781Sgibbs	int		retval;
69218781Sgibbs	u_int		n_q_required;
69318781Sgibbs	u_int32_t	addr;
69418781Sgibbs	u_int8_t	sg_entry_cnt;
69518781Sgibbs	u_int8_t	target_ix;
69618781Sgibbs	u_int8_t	sg_entry_cnt_minus_one;
69718781Sgibbs	u_int8_t	tid_no;
69818781Sgibbs
699241492Sjhb	if (!dumping)
700241492Sjhb		mtx_assert(&adv->lock, MA_OWNED);
70118781Sgibbs	scsiq->q1.q_no = 0;
70218781Sgibbs	retval = 1;  /* Default to error case */
70318781Sgibbs	target_ix = scsiq->q2.target_ix;
70418781Sgibbs	tid_no = ADV_TIX_TO_TID(target_ix);
70539217Sgibbs	tinfo = &adv->tinfo[tid_no];
70618781Sgibbs
70739217Sgibbs	if (scsiq->cdbptr[0] == REQUEST_SENSE) {
70839217Sgibbs		/* Renegotiate if appropriate. */
70939217Sgibbs		adv_set_syncrate(adv, /*struct cam_path */NULL,
71039217Sgibbs				 tid_no, /*period*/0, /*offset*/0,
71139217Sgibbs				 ADV_TRANS_CUR);
71239217Sgibbs		if (tinfo->current.period != tinfo->goal.period) {
71339217Sgibbs			adv_msgout_sdtr(adv, tinfo->goal.period,
71439217Sgibbs					tinfo->goal.offset);
71518781Sgibbs			scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
71618781Sgibbs		}
71718781Sgibbs	}
71818781Sgibbs
71918781Sgibbs	if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
72018781Sgibbs		sg_entry_cnt = scsiq->sg_head->entry_cnt;
72118781Sgibbs		sg_entry_cnt_minus_one = sg_entry_cnt - 1;
72218781Sgibbs
72318781Sgibbs#ifdef DIAGNOSTIC
72418781Sgibbs		if (sg_entry_cnt <= 1)
72539217Sgibbs			panic("adv_execute_scsi_queue: Queue "
72639217Sgibbs			      "with QC_SG_HEAD set but %d segs.", sg_entry_cnt);
72718781Sgibbs
72818781Sgibbs		if (sg_entry_cnt > ADV_MAX_SG_LIST)
72939217Sgibbs			panic("adv_execute_scsi_queue: "
73039217Sgibbs			      "Queue with too many segs.");
73118781Sgibbs
73255945Sgibbs		if ((adv->type & (ADV_ISA | ADV_VL | ADV_EISA)) != 0) {
73339505Sgibbs			int i;
73439505Sgibbs
73518781Sgibbs			for (i = 0; i < sg_entry_cnt_minus_one; i++) {
73618781Sgibbs				addr = scsiq->sg_head->sg_list[i].addr +
73718781Sgibbs				       scsiq->sg_head->sg_list[i].bytes;
73818781Sgibbs
73918781Sgibbs				if ((addr & 0x0003) != 0)
74039217Sgibbs					panic("adv_execute_scsi_queue: SG "
74139217Sgibbs					      "with odd address or byte count");
74218781Sgibbs			}
74318781Sgibbs		}
74418781Sgibbs#endif
74539217Sgibbs		p_data_addr =
74639217Sgibbs		    &scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].addr;
74739217Sgibbs		p_data_bcount =
74839217Sgibbs		    &scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].bytes;
74918781Sgibbs
75018781Sgibbs		n_q_required = adv_sgcount_to_qcount(sg_entry_cnt);
75118781Sgibbs		scsiq->sg_head->queue_cnt = n_q_required - 1;
75218781Sgibbs	} else {
75318781Sgibbs		p_data_addr = &scsiq->q1.data_addr;
75418781Sgibbs		p_data_bcount = &scsiq->q1.data_cnt;
75518781Sgibbs		n_q_required = 1;
75618781Sgibbs	}
75718781Sgibbs
75839217Sgibbs	disable_syn_offset_one_fix = FALSE;
75939217Sgibbs
76039217Sgibbs	if ((adv->fix_asyn_xfer & scsiq->q1.target_id) != 0
76139217Sgibbs	 && (adv->fix_asyn_xfer_always & scsiq->q1.target_id) == 0) {
76239217Sgibbs
76339217Sgibbs		if (datalen != 0) {
76439217Sgibbs			if (datalen < 512) {
76539217Sgibbs				disable_syn_offset_one_fix = TRUE;
76639217Sgibbs			} else {
76739217Sgibbs				if (scsiq->cdbptr[0] == INQUIRY
76839217Sgibbs				 || scsiq->cdbptr[0] == REQUEST_SENSE
76939217Sgibbs				 || scsiq->cdbptr[0] == READ_CAPACITY
77039217Sgibbs				 || scsiq->cdbptr[0] == MODE_SELECT_6
77139217Sgibbs				 || scsiq->cdbptr[0] == MODE_SENSE_6
77239217Sgibbs				 || scsiq->cdbptr[0] == MODE_SENSE_10
77339217Sgibbs				 || scsiq->cdbptr[0] == MODE_SELECT_10
77439217Sgibbs				 || scsiq->cdbptr[0] == READ_TOC) {
77539217Sgibbs					disable_syn_offset_one_fix = TRUE;
77618781Sgibbs				}
77718781Sgibbs			}
77818781Sgibbs		}
77918781Sgibbs	}
78039217Sgibbs
78139217Sgibbs	if (disable_syn_offset_one_fix) {
78239217Sgibbs		scsiq->q2.tag_code &=
78339217Sgibbs		    ~(MSG_SIMPLE_Q_TAG|MSG_HEAD_OF_Q_TAG|MSG_ORDERED_Q_TAG);
78439217Sgibbs		scsiq->q2.tag_code |= (ADV_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX
78539217Sgibbs				     | ADV_TAG_FLAG_DISABLE_DISCONNECT);
78639217Sgibbs	}
78739217Sgibbs
78839217Sgibbs	if ((adv->bug_fix_control & ADV_BUG_FIX_IF_NOT_DWB) != 0
78939217Sgibbs	 && (scsiq->cdbptr[0] == READ_10 || scsiq->cdbptr[0] == READ_6)) {
79039217Sgibbs		u_int8_t extra_bytes;
79139217Sgibbs
79239217Sgibbs		addr = *p_data_addr + *p_data_bcount;
79339217Sgibbs		extra_bytes = addr & 0x0003;
79439217Sgibbs		if (extra_bytes != 0
79539217Sgibbs		 && ((scsiq->q1.cntl & QC_SG_HEAD) != 0
79639217Sgibbs		  || (scsiq->q1.data_cnt & 0x01FF) == 0)) {
79739217Sgibbs			scsiq->q2.tag_code |= ADV_TAG_FLAG_EXTRA_BYTES;
79839217Sgibbs			scsiq->q1.extra_bytes = extra_bytes;
79939217Sgibbs			*p_data_bcount -= extra_bytes;
80039217Sgibbs		}
80139217Sgibbs	}
80239217Sgibbs
80318781Sgibbs	if ((adv_get_num_free_queues(adv, n_q_required) >= n_q_required)
80439217Sgibbs	 || ((scsiq->q1.cntl & QC_URGENT) != 0))
80518781Sgibbs		retval = adv_send_scsi_queue(adv, scsiq, n_q_required);
80618781Sgibbs
80718781Sgibbs	return (retval);
80818781Sgibbs}
80918781Sgibbs
81018781Sgibbs
81118781Sgibbsu_int8_t
81239217Sgibbsadv_copy_lram_doneq(struct adv_softc *adv, u_int16_t q_addr,
81339217Sgibbs		    struct adv_q_done_info *scsiq, u_int32_t max_dma_count)
81418781Sgibbs{
81539217Sgibbs	u_int16_t val;
81639217Sgibbs	u_int8_t  sg_queue_cnt;
81718781Sgibbs
81818781Sgibbs	adv_get_q_info(adv, q_addr + ADV_SCSIQ_DONE_INFO_BEG,
81918781Sgibbs		       (u_int16_t *)scsiq,
82018781Sgibbs		       (sizeof(scsiq->d2) + sizeof(scsiq->d3)) / 2);
82118781Sgibbs
82218781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
82318781Sgibbs	adv_adj_endian_qdone_info(scsiq);
82418781Sgibbs#endif
82518781Sgibbs
82618781Sgibbs	val = adv_read_lram_16(adv, q_addr + ADV_SCSIQ_B_STATUS);
82718781Sgibbs	scsiq->q_status = val & 0xFF;
82818781Sgibbs	scsiq->q_no = (val >> 8) & 0XFF;
82918781Sgibbs
83018781Sgibbs	val = adv_read_lram_16(adv, q_addr + ADV_SCSIQ_B_CNTL);
83118781Sgibbs	scsiq->cntl = val & 0xFF;
83218781Sgibbs	sg_queue_cnt = (val >> 8) & 0xFF;
83318781Sgibbs
83418781Sgibbs	val = adv_read_lram_16(adv,q_addr + ADV_SCSIQ_B_SENSE_LEN);
83518781Sgibbs	scsiq->sense_len = val & 0xFF;
83639217Sgibbs	scsiq->extra_bytes = (val >> 8) & 0xFF;
83718781Sgibbs
83840133Sgibbs	/*
83955945Sgibbs	 * Due to a bug in accessing LRAM on the 940UA, the residual
84055945Sgibbs	 * is split into separate high and low 16bit quantities.
84140133Sgibbs	 */
84239217Sgibbs	scsiq->remain_bytes =
84340133Sgibbs	    adv_read_lram_16(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_CNT);
84455945Sgibbs	scsiq->remain_bytes |=
84555945Sgibbs	    adv_read_lram_16(adv, q_addr + ADV_SCSIQ_W_ALT_DC1) << 16;
84655945Sgibbs
84718781Sgibbs	/*
84818781Sgibbs	 * XXX Is this just a safeguard or will the counter really
84918781Sgibbs	 * have bogus upper bits?
85018781Sgibbs	 */
85118781Sgibbs	scsiq->remain_bytes &= max_dma_count;
85218781Sgibbs
85318781Sgibbs	return (sg_queue_cnt);
85418781Sgibbs}
85518781Sgibbs
85618781Sgibbsint
85739217Sgibbsadv_start_chip(struct adv_softc *adv)
85818781Sgibbs{
85939217Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, 0);
86039217Sgibbs	if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) != 0)
86139217Sgibbs		return (0);
86239217Sgibbs	return (1);
86339217Sgibbs}
86439217Sgibbs
86539217Sgibbsint
86639217Sgibbsadv_stop_execution(struct adv_softc *adv)
86739217Sgibbs{
86818781Sgibbs	int count;
86918781Sgibbs
87018781Sgibbs	count = 0;
87118781Sgibbs	if (adv_read_lram_8(adv, ADV_STOP_CODE_B) == 0) {
87218781Sgibbs		adv_write_lram_8(adv, ADV_STOP_CODE_B,
87318781Sgibbs				 ADV_STOP_REQ_RISC_STOP);
87418781Sgibbs		do {
87518781Sgibbs			if (adv_read_lram_8(adv, ADV_STOP_CODE_B) &
87618781Sgibbs				ADV_STOP_ACK_RISC_STOP) {
87718781Sgibbs				return (1);
87818781Sgibbs			}
87918781Sgibbs			DELAY(1000);
88018781Sgibbs		} while (count++ < 20);
88118781Sgibbs	}
88218781Sgibbs	return (0);
88318781Sgibbs}
88418781Sgibbs
88518781Sgibbsint
88639217Sgibbsadv_is_chip_halted(struct adv_softc *adv)
88718781Sgibbs{
88818781Sgibbs	if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) != 0) {
88918781Sgibbs		if ((ADV_INB(adv, ADV_CHIP_CTRL) & ADV_CC_HALT) != 0) {
89018781Sgibbs			return (1);
89118781Sgibbs		}
89218781Sgibbs	}
89318781Sgibbs	return (0);
89418781Sgibbs}
89518781Sgibbs
89618781Sgibbs/*
89718781Sgibbs * XXX The numeric constants and the loops in this routine
89818781Sgibbs * need to be documented.
89918781Sgibbs */
90018781Sgibbsvoid
90139217Sgibbsadv_ack_interrupt(struct adv_softc *adv)
90218781Sgibbs{
90318781Sgibbs	u_int8_t	host_flag;
90418781Sgibbs	u_int8_t	risc_flag;
90518781Sgibbs	int		loop;
90618781Sgibbs
90718781Sgibbs	loop = 0;
90818781Sgibbs	do {
90918781Sgibbs		risc_flag = adv_read_lram_8(adv, ADVV_RISC_FLAG_B);
91018781Sgibbs		if (loop++ > 0x7FFF) {
91118781Sgibbs			break;
91218781Sgibbs		}
91318781Sgibbs	} while ((risc_flag & ADV_RISC_FLAG_GEN_INT) != 0);
91418781Sgibbs
91518781Sgibbs	host_flag = adv_read_lram_8(adv, ADVV_HOST_FLAG_B);
91618781Sgibbs	adv_write_lram_8(adv, ADVV_HOST_FLAG_B,
91718781Sgibbs			 host_flag | ADV_HOST_FLAG_ACK_INT);
91818781Sgibbs
91918781Sgibbs	ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_INT_ACK);
92018781Sgibbs	loop = 0;
92118781Sgibbs	while (ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_INT_PENDING) {
92218781Sgibbs		ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_INT_ACK);
92318781Sgibbs		if (loop++ > 3) {
92418781Sgibbs			break;
92518781Sgibbs		}
92618781Sgibbs	}
92718781Sgibbs
92818781Sgibbs	adv_write_lram_8(adv, ADVV_HOST_FLAG_B, host_flag);
92918781Sgibbs}
93018781Sgibbs
93118781Sgibbs/*
93218781Sgibbs * Handle all conditions that may halt the chip waiting
93318781Sgibbs * for us to intervene.
93418781Sgibbs */
93518781Sgibbsvoid
93639217Sgibbsadv_isr_chip_halted(struct adv_softc *adv)
93718781Sgibbs{
93818781Sgibbs	u_int16_t	  int_halt_code;
93939217Sgibbs	u_int16_t	  halt_q_addr;
94039217Sgibbs	target_bit_vector target_mask;
94139217Sgibbs	target_bit_vector scsi_busy;
94218781Sgibbs	u_int8_t	  halt_qp;
94318781Sgibbs	u_int8_t	  target_ix;
94418781Sgibbs	u_int8_t	  q_cntl;
94518781Sgibbs	u_int8_t	  tid_no;
94618781Sgibbs
947241492Sjhb	if (!dumping)
948241492Sjhb		mtx_assert(&adv->lock, MA_OWNED);
94918781Sgibbs	int_halt_code = adv_read_lram_16(adv, ADVV_HALTCODE_W);
95018781Sgibbs	halt_qp = adv_read_lram_8(adv, ADVV_CURCDB_B);
95118781Sgibbs	halt_q_addr = ADV_QNO_TO_QADDR(halt_qp);
95218781Sgibbs	target_ix = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_TARGET_IX);
95318781Sgibbs	q_cntl = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL);
95418781Sgibbs	tid_no = ADV_TIX_TO_TID(target_ix);
95539217Sgibbs	target_mask = ADV_TID_TO_TARGET_MASK(tid_no);
95639217Sgibbs	if (int_halt_code == ADV_HALT_DISABLE_ASYN_USE_SYN_FIX) {
95718781Sgibbs		/*
95839217Sgibbs		 * Temporarily disable the async fix by removing
95939217Sgibbs		 * this target from the list of affected targets,
96039217Sgibbs		 * setting our async rate, and then putting us
96139217Sgibbs		 * back into the mask.
96218781Sgibbs		 */
96339217Sgibbs		adv->fix_asyn_xfer &= ~target_mask;
96439217Sgibbs		adv_set_syncrate(adv, /*struct cam_path */NULL,
96539217Sgibbs				 tid_no, /*period*/0, /*offset*/0,
96639217Sgibbs				 ADV_TRANS_ACTIVE);
96739217Sgibbs		adv->fix_asyn_xfer |= target_mask;
96839217Sgibbs	} else if (int_halt_code == ADV_HALT_ENABLE_ASYN_USE_SYN_FIX) {
96939217Sgibbs		adv_set_syncrate(adv, /*struct cam_path */NULL,
97039217Sgibbs				 tid_no, /*period*/0, /*offset*/0,
97139217Sgibbs				 ADV_TRANS_ACTIVE);
97239217Sgibbs	} else if (int_halt_code == ADV_HALT_EXTMSG_IN) {
97339217Sgibbs		adv_handle_extmsg_in(adv, halt_q_addr, q_cntl,
97439217Sgibbs				     target_mask, tid_no);
97518781Sgibbs	} else if (int_halt_code == ADV_HALT_CHK_CONDITION) {
97655945Sgibbs		struct	  adv_target_transinfo* tinfo;
977241492Sjhb		struct	  adv_ccb_info *cinfo;
97855945Sgibbs		union	  ccb *ccb;
97955945Sgibbs		u_int32_t cinfo_index;
98055945Sgibbs		u_int8_t  tag_code;
98155945Sgibbs		u_int8_t  q_status;
98218781Sgibbs
98339217Sgibbs		tinfo = &adv->tinfo[tid_no];
98418781Sgibbs		q_cntl |= QC_REQ_SENSE;
98518781Sgibbs
98639217Sgibbs		/* Renegotiate if appropriate. */
98739217Sgibbs		adv_set_syncrate(adv, /*struct cam_path */NULL,
98839217Sgibbs				 tid_no, /*period*/0, /*offset*/0,
98939217Sgibbs				 ADV_TRANS_CUR);
99039217Sgibbs		if (tinfo->current.period != tinfo->goal.period) {
99139217Sgibbs			adv_msgout_sdtr(adv, tinfo->goal.period,
99239217Sgibbs					tinfo->goal.offset);
99318781Sgibbs			q_cntl |= QC_MSG_OUT;
99418781Sgibbs		}
99518781Sgibbs		adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl);
99618781Sgibbs
99718781Sgibbs		/* Don't tag request sense commands */
99839217Sgibbs		tag_code = adv_read_lram_8(adv,
99939217Sgibbs					   halt_q_addr + ADV_SCSIQ_B_TAG_CODE);
100039217Sgibbs		tag_code &=
100139217Sgibbs		    ~(MSG_SIMPLE_Q_TAG|MSG_HEAD_OF_Q_TAG|MSG_ORDERED_Q_TAG);
100218781Sgibbs
100339217Sgibbs		if ((adv->fix_asyn_xfer & target_mask) != 0
100439217Sgibbs		 && (adv->fix_asyn_xfer_always & target_mask) == 0) {
100539217Sgibbs			tag_code |= (ADV_TAG_FLAG_DISABLE_DISCONNECT
100639217Sgibbs				 | ADV_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
100739217Sgibbs		}
100839217Sgibbs		adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_TAG_CODE,
100939217Sgibbs				 tag_code);
101039217Sgibbs		q_status = adv_read_lram_8(adv,
101139217Sgibbs					   halt_q_addr + ADV_SCSIQ_B_STATUS);
101218781Sgibbs		q_status |= (QS_READY | QS_BUSY);
101339217Sgibbs		adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_STATUS,
101439217Sgibbs				 q_status);
101539217Sgibbs		/*
101639217Sgibbs		 * Freeze the devq until we can handle the sense condition.
101739217Sgibbs		 */
101855945Sgibbs		cinfo_index =
101955945Sgibbs		    adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX);
1020241492Sjhb		cinfo = &adv->ccb_infos[cinfo_index];
102155945Sgibbs		ccb = adv->ccb_infos[cinfo_index].ccb;
102239217Sgibbs		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
102339217Sgibbs		ccb->ccb_h.status |= CAM_DEV_QFRZN;
102439217Sgibbs		adv_abort_ccb(adv, tid_no, ADV_TIX_TO_LUN(target_ix),
102539217Sgibbs			      /*ccb*/NULL, CAM_REQUEUE_REQ,
102639217Sgibbs			      /*queued_only*/TRUE);
102718781Sgibbs		scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B);
102839217Sgibbs		scsi_busy &= ~target_mask;
102918781Sgibbs		adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy);
103045846Sgibbs		/*
103145846Sgibbs		 * Ensure we have enough time to actually
103245846Sgibbs		 * retrieve the sense.
103345846Sgibbs		 */
1034241492Sjhb		callout_reset(&cinfo->timer, 5 * hz, adv_timeout, ccb);
103518781Sgibbs	} else if (int_halt_code == ADV_HALT_SDTR_REJECTED) {
103639217Sgibbs		struct	ext_msg out_msg;
103718781Sgibbs
103818781Sgibbs		adv_read_lram_16_multi(adv, ADVV_MSGOUT_BEG,
103918781Sgibbs				       (u_int16_t *) &out_msg,
104018781Sgibbs				       sizeof(out_msg)/2);
104118781Sgibbs
104239217Sgibbs		if ((out_msg.msg_type == MSG_EXTENDED)
104339217Sgibbs		 && (out_msg.msg_len == MSG_EXT_SDTR_LEN)
104439217Sgibbs		 && (out_msg.msg_req == MSG_EXT_SDTR)) {
104518781Sgibbs
104639217Sgibbs			/* Revert to Async */
104739217Sgibbs			adv_set_syncrate(adv, /*struct cam_path */NULL,
104839217Sgibbs					 tid_no, /*period*/0, /*offset*/0,
104939217Sgibbs					 ADV_TRANS_GOAL|ADV_TRANS_ACTIVE);
105018781Sgibbs		}
105118781Sgibbs		q_cntl &= ~QC_MSG_OUT;
105218781Sgibbs		adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl);
105318781Sgibbs	} else if (int_halt_code == ADV_HALT_SS_QUEUE_FULL) {
105439217Sgibbs		union ccb *ccb;
105555945Sgibbs		u_int32_t cinfo_index;
105639217Sgibbs
1057263954Simp		adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_SCSI_STATUS);
105855945Sgibbs		cinfo_index =
105955945Sgibbs		    adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX);
106055945Sgibbs		ccb = adv->ccb_infos[cinfo_index].ccb;
106139217Sgibbs		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
106240733Sgibbs		ccb->ccb_h.status |= CAM_DEV_QFRZN|CAM_SCSI_STATUS_ERROR;
106340733Sgibbs		ccb->csio.scsi_status = SCSI_STATUS_QUEUE_FULL;
106439217Sgibbs		adv_abort_ccb(adv, tid_no, ADV_TIX_TO_LUN(target_ix),
106539217Sgibbs			      /*ccb*/NULL, CAM_REQUEUE_REQ,
106639217Sgibbs			      /*queued_only*/TRUE);
106739217Sgibbs		scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B);
106839217Sgibbs		scsi_busy &= ~target_mask;
106939217Sgibbs		adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy);
107055945Sgibbs	} else {
107155945Sgibbs		printf("Unhandled Halt Code %x\n", int_halt_code);
107239217Sgibbs	}
107339217Sgibbs	adv_write_lram_16(adv, ADVV_HALTCODE_W, 0);
107439217Sgibbs}
107518781Sgibbs
107639217Sgibbsvoid
107739217Sgibbsadv_sdtr_to_period_offset(struct adv_softc *adv,
107839217Sgibbs			  u_int8_t sync_data, u_int8_t *period,
107939217Sgibbs			  u_int8_t *offset, int tid)
108039217Sgibbs{
108139217Sgibbs	if (adv->fix_asyn_xfer & ADV_TID_TO_TARGET_MASK(tid)
108239217Sgibbs	 && (sync_data == ASYN_SDTR_DATA_FIX_PCI_REV_AB)) {
108339217Sgibbs		*period = *offset = 0;
108439217Sgibbs	} else {
108539217Sgibbs		*period = adv->sdtr_period_tbl[((sync_data >> 4) & 0xF)];
108639217Sgibbs		*offset = sync_data & 0xF;
108739217Sgibbs	}
108839217Sgibbs}
108939217Sgibbs
109039217Sgibbsvoid
109139217Sgibbsadv_set_syncrate(struct adv_softc *adv, struct cam_path *path,
109239217Sgibbs		 u_int tid, u_int period, u_int offset, u_int type)
109339217Sgibbs{
109439217Sgibbs	struct adv_target_transinfo* tinfo;
109539217Sgibbs	u_int old_period;
109639217Sgibbs	u_int old_offset;
109739217Sgibbs	u_int8_t sdtr_data;
109839217Sgibbs
1099241492Sjhb	mtx_assert(&adv->lock, MA_OWNED);
110039217Sgibbs	tinfo = &adv->tinfo[tid];
110139217Sgibbs
110239217Sgibbs	/* Filter our input */
110339217Sgibbs	sdtr_data = adv_period_offset_to_sdtr(adv, &period,
110439217Sgibbs					      &offset, tid);
110539217Sgibbs
110639217Sgibbs	old_period = tinfo->current.period;
110739217Sgibbs	old_offset = tinfo->current.offset;
110839217Sgibbs
110939217Sgibbs	if ((type & ADV_TRANS_CUR) != 0
111039217Sgibbs	 && ((old_period != period || old_offset != offset)
111139217Sgibbs	  || period == 0 || offset == 0) /*Changes in asyn fix settings*/) {
111239217Sgibbs		int halted;
111339217Sgibbs
111439217Sgibbs		halted = adv_is_chip_halted(adv);
111539217Sgibbs		if (halted == 0)
111639217Sgibbs			/* Must halt the chip first */
111739217Sgibbs			adv_host_req_chip_halt(adv);
111839217Sgibbs
111939217Sgibbs		/* Update current hardware settings */
112039217Sgibbs		adv_set_sdtr_reg_at_id(adv, tid, sdtr_data);
112139217Sgibbs
112218781Sgibbs		/*
112339217Sgibbs		 * If a target can run in sync mode, we don't need
112439217Sgibbs		 * to check it for sync problems.
112518781Sgibbs		 */
112639217Sgibbs		if (offset != 0)
112739217Sgibbs			adv->fix_asyn_xfer &= ~ADV_TID_TO_TARGET_MASK(tid);
112818781Sgibbs
112939217Sgibbs		if (halted == 0)
113039217Sgibbs			/* Start the chip again */
113139217Sgibbs			adv_start_chip(adv);
113218781Sgibbs
113339217Sgibbs		tinfo->current.period = period;
113439217Sgibbs		tinfo->current.offset = offset;
113539217Sgibbs
113639217Sgibbs		if (path != NULL) {
113739217Sgibbs			/*
113839217Sgibbs			 * Tell the SCSI layer about the
113939217Sgibbs			 * new transfer parameters.
114039217Sgibbs			 */
114139217Sgibbs			struct	ccb_trans_settings neg;
1142163816Smjacob			memset(&neg, 0, sizeof (neg));
1143163816Smjacob			struct ccb_trans_settings_spi *spi =
1144163816Smjacob			    &neg.xport_specific.spi;
114539217Sgibbs
1146163816Smjacob			neg.protocol = PROTO_SCSI;
1147163816Smjacob			neg.protocol_version = SCSI_REV_2;
1148163816Smjacob			neg.transport = XPORT_SPI;
1149163816Smjacob			neg.transport_version = 2;
1150163816Smjacob
1151163816Smjacob			spi->sync_offset = offset;
1152163816Smjacob			spi->sync_period = period;
1153163816Smjacob			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
1154163816Smjacob			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
115539217Sgibbs			xpt_setup_ccb(&neg.ccb_h, path, /*priority*/1);
115639217Sgibbs			xpt_async(AC_TRANSFER_NEG, path, &neg);
115739217Sgibbs		}
115839217Sgibbs	}
115939217Sgibbs
116039217Sgibbs	if ((type & ADV_TRANS_GOAL) != 0) {
116139217Sgibbs		tinfo->goal.period = period;
116239217Sgibbs		tinfo->goal.offset = offset;
116339217Sgibbs	}
116439217Sgibbs
116539217Sgibbs	if ((type & ADV_TRANS_USER) != 0) {
116639217Sgibbs		tinfo->user.period = period;
116739217Sgibbs		tinfo->user.offset = offset;
116839217Sgibbs	}
116939217Sgibbs}
117039217Sgibbs
117139217Sgibbsu_int8_t
117239217Sgibbsadv_period_offset_to_sdtr(struct adv_softc *adv, u_int *period,
117339217Sgibbs			  u_int *offset, int tid)
117439217Sgibbs{
117539217Sgibbs	u_int i;
117639217Sgibbs	u_int dummy_offset;
117739217Sgibbs	u_int dummy_period;
117839217Sgibbs
117939217Sgibbs	if (offset == NULL) {
118039217Sgibbs		dummy_offset = 0;
118139217Sgibbs		offset = &dummy_offset;
118239217Sgibbs	}
118339217Sgibbs
118439217Sgibbs	if (period == NULL) {
118539217Sgibbs		dummy_period = 0;
118639217Sgibbs		period = &dummy_period;
118739217Sgibbs	}
118839217Sgibbs
118939217Sgibbs	*offset = MIN(ADV_SYN_MAX_OFFSET, *offset);
119039217Sgibbs	if (*period != 0 && *offset != 0) {
119139217Sgibbs		for (i = 0; i < adv->sdtr_period_tbl_size; i++) {
119239217Sgibbs			if (*period <= adv->sdtr_period_tbl[i]) {
119339217Sgibbs				/*
119439217Sgibbs				 * When responding to a target that requests
119539217Sgibbs				 * sync, the requested  rate may fall between
119639217Sgibbs				 * two rates that we can output, but still be
119739217Sgibbs				 * a rate that we can receive.  Because of this,
119839217Sgibbs				 * we want to respond to the target with
119939217Sgibbs				 * the same rate that it sent to us even
120039217Sgibbs				 * if the period we use to send data to it
120139217Sgibbs				 * is lower.  Only lower the response period
120239217Sgibbs				 * if we must.
120339217Sgibbs				 */
120439217Sgibbs				if (i == 0 /* Our maximum rate */)
120539217Sgibbs					*period = adv->sdtr_period_tbl[0];
120639217Sgibbs				return ((i << 4) | *offset);
120718781Sgibbs			}
120818781Sgibbs		}
120918781Sgibbs	}
121039217Sgibbs
121139217Sgibbs	/* Must go async */
121239217Sgibbs	*period = 0;
121339217Sgibbs	*offset = 0;
121439217Sgibbs	if (adv->fix_asyn_xfer & ADV_TID_TO_TARGET_MASK(tid))
121539217Sgibbs		return (ASYN_SDTR_DATA_FIX_PCI_REV_AB);
121639217Sgibbs	return (0);
121718781Sgibbs}
121818781Sgibbs
121918781Sgibbs/* Internal Routines */
122018781Sgibbs
122118781Sgibbsstatic void
122239217Sgibbsadv_read_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr,
122339217Sgibbs		       u_int16_t *buffer, int count)
122418781Sgibbs{
122518781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
122618781Sgibbs	ADV_INSW(adv, ADV_LRAM_DATA, buffer, count);
122718781Sgibbs}
122818781Sgibbs
122918781Sgibbsstatic void
123039217Sgibbsadv_write_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr,
123139217Sgibbs			u_int16_t *buffer, int count)
123218781Sgibbs{
123318781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
123418781Sgibbs	ADV_OUTSW(adv, ADV_LRAM_DATA, buffer, count);
123518781Sgibbs}
123618781Sgibbs
123718781Sgibbsstatic void
123839217Sgibbsadv_mset_lram_16(struct adv_softc *adv, u_int16_t s_addr,
123939217Sgibbs		 u_int16_t set_value, int count)
124018781Sgibbs{
124118781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
1242241492Sjhb	bus_set_multi_2(adv->res, adv->reg_off + ADV_LRAM_DATA,
1243241492Sjhb	    set_value, count);
124418781Sgibbs}
124518781Sgibbs
124618781Sgibbsstatic u_int32_t
124739217Sgibbsadv_msum_lram_16(struct adv_softc *adv, u_int16_t s_addr, int count)
124818781Sgibbs{
124918781Sgibbs	u_int32_t	sum;
125018781Sgibbs	int		i;
125118781Sgibbs
125218781Sgibbs	sum = 0;
125339217Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
125439217Sgibbs	for (i = 0; i < count; i++)
125539217Sgibbs		sum += ADV_INW(adv, ADV_LRAM_DATA);
125618781Sgibbs	return (sum);
125718781Sgibbs}
125818781Sgibbs
125918781Sgibbsstatic int
126039217Sgibbsadv_write_and_verify_lram_16(struct adv_softc *adv, u_int16_t addr,
126139217Sgibbs			     u_int16_t value)
126218781Sgibbs{
126318781Sgibbs	int	retval;
126418781Sgibbs
126518781Sgibbs	retval = 0;
126618781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
126718781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, value);
126839217Sgibbs	DELAY(10000);
126918781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
127018781Sgibbs	if (value != ADV_INW(adv, ADV_LRAM_DATA))
127118781Sgibbs		retval = 1;
127218781Sgibbs	return (retval);
127318781Sgibbs}
127418781Sgibbs
127518781Sgibbsstatic u_int32_t
127639217Sgibbsadv_read_lram_32(struct adv_softc *adv, u_int16_t addr)
127718781Sgibbs{
127818781Sgibbs	u_int16_t           val_low, val_high;
127918781Sgibbs
128018781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
128118781Sgibbs
128218781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
128318781Sgibbs	val_high = ADV_INW(adv, ADV_LRAM_DATA);
128418781Sgibbs	val_low = ADV_INW(adv, ADV_LRAM_DATA);
128518781Sgibbs#else
128618781Sgibbs	val_low = ADV_INW(adv, ADV_LRAM_DATA);
128718781Sgibbs	val_high = ADV_INW(adv, ADV_LRAM_DATA);
128818781Sgibbs#endif
128918781Sgibbs
129018781Sgibbs	return (((u_int32_t)val_high << 16) | (u_int32_t)val_low);
129118781Sgibbs}
129218781Sgibbs
129318781Sgibbsstatic void
129439217Sgibbsadv_write_lram_32(struct adv_softc *adv, u_int16_t addr, u_int32_t value)
129518781Sgibbs{
129618781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
129718781Sgibbs
129818781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
129918781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)((value >> 16) & 0xFFFF));
130018781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)(value & 0xFFFF));
130118781Sgibbs#else
130218781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)(value & 0xFFFF));
130318781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)((value >> 16) & 0xFFFF));
130418781Sgibbs#endif
130518781Sgibbs}
130618781Sgibbs
130718781Sgibbsstatic void
130839217Sgibbsadv_write_lram_32_multi(struct adv_softc *adv, u_int16_t s_addr,
130939217Sgibbs			u_int32_t *buffer, int count)
131018781Sgibbs{
131118781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
131239217Sgibbs	ADV_OUTSW(adv, ADV_LRAM_DATA, (u_int16_t *)buffer, count * 2);
131318781Sgibbs}
131418781Sgibbs
131518781Sgibbsstatic u_int16_t
131639217Sgibbsadv_read_eeprom_16(struct adv_softc *adv, u_int8_t addr)
131718781Sgibbs{
131818781Sgibbs	u_int16_t read_wval;
131918781Sgibbs	u_int8_t  cmd_reg;
132018781Sgibbs
132118781Sgibbs	adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_DISABLE);
132218781Sgibbs	DELAY(1000);
132318781Sgibbs	cmd_reg = addr | ADV_EEPROM_CMD_READ;
132418781Sgibbs	adv_write_eeprom_cmd_reg(adv, cmd_reg);
132518781Sgibbs	DELAY(1000);
132618781Sgibbs	read_wval = ADV_INW(adv, ADV_EEPROM_DATA);
132718781Sgibbs	DELAY(1000);
132818781Sgibbs	return (read_wval);
132918781Sgibbs}
133018781Sgibbs
133118781Sgibbsstatic u_int16_t
133239217Sgibbsadv_write_eeprom_16(struct adv_softc *adv, u_int8_t addr, u_int16_t value)
133318781Sgibbs{
133418781Sgibbs	u_int16_t	read_value;
133518781Sgibbs
133618781Sgibbs	read_value = adv_read_eeprom_16(adv, addr);
133718781Sgibbs	if (read_value != value) {
133818781Sgibbs		adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_ENABLE);
133918781Sgibbs		DELAY(1000);
134018781Sgibbs
134118781Sgibbs		ADV_OUTW(adv, ADV_EEPROM_DATA, value);
134218781Sgibbs		DELAY(1000);
134318781Sgibbs
134418781Sgibbs		adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE | addr);
134518781Sgibbs		DELAY(20 * 1000);
134618781Sgibbs
134718781Sgibbs		adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_DISABLE);
134818781Sgibbs		DELAY(1000);
134918781Sgibbs		read_value = adv_read_eeprom_16(adv, addr);
135018781Sgibbs	}
135118781Sgibbs	return (read_value);
135218781Sgibbs}
135318781Sgibbs
135418781Sgibbsstatic int
135539217Sgibbsadv_write_eeprom_cmd_reg(struct adv_softc *adv, u_int8_t cmd_reg)
135618781Sgibbs{
135718781Sgibbs	u_int8_t read_back;
135818781Sgibbs	int	 retry;
135918781Sgibbs
136018781Sgibbs	retry = 0;
136118781Sgibbs	while (1) {
136218781Sgibbs		ADV_OUTB(adv, ADV_EEPROM_CMD, cmd_reg);
136318781Sgibbs		DELAY(1000);
136418781Sgibbs		read_back = ADV_INB(adv, ADV_EEPROM_CMD);
136518781Sgibbs		if (read_back == cmd_reg) {
136618781Sgibbs			return (1);
136718781Sgibbs		}
136818781Sgibbs		if (retry++ > ADV_EEPROM_MAX_RETRY) {
136918781Sgibbs			return (0);
137018781Sgibbs		}
137118781Sgibbs	}
137218781Sgibbs}
137318781Sgibbs
137418781Sgibbsstatic int
137539217Sgibbsadv_set_eeprom_config_once(struct adv_softc *adv,
137639217Sgibbs			   struct adv_eeprom_config *eeprom_config)
137718781Sgibbs{
137818781Sgibbs	int		n_error;
137918781Sgibbs	u_int16_t	*wbuf;
138018781Sgibbs	u_int16_t	sum;
138118781Sgibbs	u_int8_t	s_addr;
138218781Sgibbs	u_int8_t	cfg_beg;
138318781Sgibbs	u_int8_t	cfg_end;
138418781Sgibbs
138518781Sgibbs	wbuf = (u_int16_t *)eeprom_config;
138618781Sgibbs	n_error = 0;
138718781Sgibbs	sum = 0;
138818781Sgibbs	for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
138918781Sgibbs		sum += *wbuf;
139018781Sgibbs		if (*wbuf != adv_write_eeprom_16(adv, s_addr, *wbuf)) {
139118781Sgibbs			n_error++;
139218781Sgibbs		}
139318781Sgibbs	}
139418781Sgibbs	if (adv->type & ADV_VL) {
139518781Sgibbs		cfg_beg = ADV_EEPROM_CFG_BEG_VL;
139618781Sgibbs		cfg_end = ADV_EEPROM_MAX_ADDR_VL;
139718781Sgibbs	} else {
139818781Sgibbs		cfg_beg = ADV_EEPROM_CFG_BEG;
139918781Sgibbs		cfg_end = ADV_EEPROM_MAX_ADDR;
140018781Sgibbs	}
140118781Sgibbs
140218781Sgibbs	for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
140318781Sgibbs		sum += *wbuf;
140418781Sgibbs		if (*wbuf != adv_write_eeprom_16(adv, s_addr, *wbuf)) {
140518781Sgibbs			n_error++;
140618781Sgibbs		}
140718781Sgibbs	}
140818781Sgibbs	*wbuf = sum;
140918781Sgibbs	if (sum != adv_write_eeprom_16(adv, s_addr, sum)) {
141018781Sgibbs		n_error++;
141118781Sgibbs	}
141218781Sgibbs	wbuf = (u_int16_t *)eeprom_config;
141318781Sgibbs	for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
141418781Sgibbs		if (*wbuf != adv_read_eeprom_16(adv, s_addr)) {
141518781Sgibbs			n_error++;
141618781Sgibbs		}
141718781Sgibbs	}
141818781Sgibbs	for (s_addr = cfg_beg; s_addr <= cfg_end; s_addr++, wbuf++) {
141918781Sgibbs		if (*wbuf != adv_read_eeprom_16(adv, s_addr)) {
142018781Sgibbs			n_error++;
142118781Sgibbs		}
142218781Sgibbs	}
142318781Sgibbs	return (n_error);
142418781Sgibbs}
142518781Sgibbs
142618781Sgibbsstatic u_int32_t
142739217Sgibbsadv_load_microcode(struct adv_softc *adv, u_int16_t s_addr,
142839217Sgibbs		   u_int16_t *mcode_buf, u_int16_t mcode_size)
142918781Sgibbs{
143039217Sgibbs	u_int32_t chksum;
143139217Sgibbs	u_int16_t mcode_lram_size;
143239217Sgibbs	u_int16_t mcode_chksum;
143318781Sgibbs
143418781Sgibbs	mcode_lram_size = mcode_size >> 1;
143518781Sgibbs	/* XXX Why zero the memory just before you write the whole thing?? */
143639217Sgibbs	adv_mset_lram_16(adv, s_addr, 0, mcode_lram_size);
143718781Sgibbs	adv_write_lram_16_multi(adv, s_addr, mcode_buf, mcode_lram_size);
143818781Sgibbs
143918781Sgibbs	chksum = adv_msum_lram_16(adv, s_addr, mcode_lram_size);
144018781Sgibbs	mcode_chksum = (u_int16_t)adv_msum_lram_16(adv, ADV_CODE_SEC_BEG,
144139217Sgibbs						   ((mcode_size - s_addr
144239217Sgibbs						     - ADV_CODE_SEC_BEG) >> 1));
144318781Sgibbs	adv_write_lram_16(adv, ADVV_MCODE_CHKSUM_W, mcode_chksum);
144418781Sgibbs	adv_write_lram_16(adv, ADVV_MCODE_SIZE_W, mcode_size);
144518781Sgibbs	return (chksum);
144618781Sgibbs}
144718781Sgibbs
144818781Sgibbsstatic void
144939217Sgibbsadv_reinit_lram(struct adv_softc *adv) {
145039217Sgibbs	adv_init_lram(adv);
145139217Sgibbs	adv_init_qlink_var(adv);
145239217Sgibbs}
145339217Sgibbs
145439217Sgibbsstatic void
145539217Sgibbsadv_init_lram(struct adv_softc *adv)
145618781Sgibbs{
145739217Sgibbs	u_int8_t  i;
145839217Sgibbs	u_int16_t s_addr;
145918781Sgibbs
146018781Sgibbs	adv_mset_lram_16(adv, ADV_QADR_BEG, 0,
146139217Sgibbs			 (((adv->max_openings + 2 + 1) * 64) >> 1));
146218781Sgibbs
146318781Sgibbs	i = ADV_MIN_ACTIVE_QNO;
146418781Sgibbs	s_addr = ADV_QADR_BEG + ADV_QBLK_SIZE;
146518781Sgibbs
146618781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD,	i + 1);
146718781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, adv->max_openings);
146818781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i);
146918781Sgibbs	i++;
147018781Sgibbs	s_addr += ADV_QBLK_SIZE;
147118781Sgibbs	for (; i < adv->max_openings; i++, s_addr += ADV_QBLK_SIZE) {
147218781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i + 1);
147318781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, i - 1);
147418781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i);
147518781Sgibbs	}
147618781Sgibbs
147718781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, ADV_QLINK_END);
147818781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, adv->max_openings - 1);
147918781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, adv->max_openings);
148018781Sgibbs	i++;
148118781Sgibbs	s_addr += ADV_QBLK_SIZE;
148218781Sgibbs
148318781Sgibbs	for (; i <= adv->max_openings + 3; i++, s_addr += ADV_QBLK_SIZE) {
148418781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i);
148518781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, i);
148618781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i);
148718781Sgibbs	}
148818781Sgibbs}
148918781Sgibbs
149018781Sgibbsstatic int
149139217Sgibbsadv_init_microcode_var(struct adv_softc *adv)
149218781Sgibbs{
149339217Sgibbs	int	 i;
149418781Sgibbs
149518781Sgibbs	for (i = 0; i <= ADV_MAX_TID; i++) {
149639217Sgibbs
149739217Sgibbs		/* Start out async all around */
149839217Sgibbs		adv_set_syncrate(adv, /*path*/NULL,
149939217Sgibbs				 i, 0, 0,
150039217Sgibbs				 ADV_TRANS_GOAL|ADV_TRANS_CUR);
150118781Sgibbs	}
150218781Sgibbs
150318781Sgibbs	adv_init_qlink_var(adv);
150418781Sgibbs
150518781Sgibbs	adv_write_lram_8(adv, ADVV_DISC_ENABLE_B, adv->disc_enable);
150618781Sgibbs	adv_write_lram_8(adv, ADVV_HOSTSCSI_ID_B, 0x01 << adv->scsi_id);
150718781Sgibbs
150839217Sgibbs	adv_write_lram_32(adv, ADVV_OVERRUN_PADDR_D, adv->overrun_physbase);
150918781Sgibbs
151039217Sgibbs	adv_write_lram_32(adv, ADVV_OVERRUN_BSIZE_D, ADV_OVERRUN_BSIZE);
151118781Sgibbs
151218781Sgibbs	ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR);
151318781Sgibbs	if (ADV_INW(adv, ADV_REG_PROG_COUNTER) != ADV_MCODE_START_ADDR) {
1514241492Sjhb		device_printf(adv->dev,
1515241492Sjhb		    "Unable to set program counter. Aborting.\n");
151618781Sgibbs		return (1);
151718781Sgibbs	}
151818781Sgibbs	return (0);
151918781Sgibbs}
152018781Sgibbs
152118781Sgibbsstatic void
152239217Sgibbsadv_init_qlink_var(struct adv_softc *adv)
152318781Sgibbs{
152418781Sgibbs	int	  i;
152518781Sgibbs	u_int16_t lram_addr;
152618781Sgibbs
152718781Sgibbs	adv_write_lram_8(adv, ADVV_NEXTRDY_B, 1);
152818781Sgibbs	adv_write_lram_8(adv, ADVV_DONENEXT_B, adv->max_openings);
152918781Sgibbs
153018781Sgibbs	adv_write_lram_16(adv, ADVV_FREE_Q_HEAD_W, 1);
153118781Sgibbs	adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, adv->max_openings);
153218781Sgibbs
153318781Sgibbs	adv_write_lram_8(adv, ADVV_BUSY_QHEAD_B,
153418781Sgibbs			 (u_int8_t)((int) adv->max_openings + 1));
153518781Sgibbs	adv_write_lram_8(adv, ADVV_DISC1_QHEAD_B,
153618781Sgibbs			 (u_int8_t)((int) adv->max_openings + 2));
153718781Sgibbs
153818781Sgibbs	adv_write_lram_8(adv, ADVV_TOTAL_READY_Q_B, adv->max_openings);
153918781Sgibbs
154018781Sgibbs	adv_write_lram_16(adv, ADVV_ASCDVC_ERR_CODE_W, 0);
154118781Sgibbs	adv_write_lram_16(adv, ADVV_HALTCODE_W, 0);
154218781Sgibbs	adv_write_lram_8(adv, ADVV_STOP_CODE_B, 0);
154318781Sgibbs	adv_write_lram_8(adv, ADVV_SCSIBUSY_B, 0);
154418781Sgibbs	adv_write_lram_8(adv, ADVV_WTM_FLAG_B, 0);
154539217Sgibbs	adv_write_lram_8(adv, ADVV_Q_DONE_IN_PROGRESS_B, 0);
154618781Sgibbs
154718781Sgibbs	lram_addr = ADV_QADR_BEG;
154818781Sgibbs	for (i = 0; i < 32; i++, lram_addr += 2)
154918781Sgibbs		adv_write_lram_16(adv, lram_addr, 0);
155018781Sgibbs}
155139217Sgibbs
155218781Sgibbsstatic void
155339217Sgibbsadv_disable_interrupt(struct adv_softc *adv)
155418781Sgibbs{
155518781Sgibbs	u_int16_t cfg;
155618781Sgibbs
155718781Sgibbs	cfg = ADV_INW(adv, ADV_CONFIG_LSW);
155818781Sgibbs	ADV_OUTW(adv, ADV_CONFIG_LSW, cfg & ~ADV_CFG_LSW_HOST_INT_ON);
155918781Sgibbs}
156018781Sgibbs
156118781Sgibbsstatic void
156239217Sgibbsadv_enable_interrupt(struct adv_softc *adv)
156318781Sgibbs{
156418781Sgibbs	u_int16_t cfg;
156518781Sgibbs
156618781Sgibbs	cfg = ADV_INW(adv, ADV_CONFIG_LSW);
156718781Sgibbs	ADV_OUTW(adv, ADV_CONFIG_LSW, cfg | ADV_CFG_LSW_HOST_INT_ON);
156818781Sgibbs}
156918781Sgibbs
157018781Sgibbsstatic void
157139217Sgibbsadv_toggle_irq_act(struct adv_softc *adv)
157218781Sgibbs{
157318781Sgibbs	ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_IRQ_ACT);
157418781Sgibbs	ADV_OUTW(adv, ADV_CHIP_STATUS, 0);
157518781Sgibbs}
157618781Sgibbs
157739217Sgibbsvoid
157839217Sgibbsadv_start_execution(struct adv_softc *adv)
157918781Sgibbs{
158018781Sgibbs	if (adv_read_lram_8(adv, ADV_STOP_CODE_B) != 0) {
158118781Sgibbs		adv_write_lram_8(adv, ADV_STOP_CODE_B, 0);
158218781Sgibbs	}
158318781Sgibbs}
158418781Sgibbs
158555945Sgibbsint
158639217Sgibbsadv_stop_chip(struct adv_softc *adv)
158718781Sgibbs{
158818781Sgibbs	u_int8_t cc_val;
158918781Sgibbs
159018781Sgibbs	cc_val = ADV_INB(adv, ADV_CHIP_CTRL)
159118781Sgibbs		 & (~(ADV_CC_SINGLE_STEP | ADV_CC_TEST | ADV_CC_DIAG));
159218781Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, cc_val | ADV_CC_HALT);
159318781Sgibbs	adv_set_chip_ih(adv, ADV_INS_HALT);
159418781Sgibbs	adv_set_chip_ih(adv, ADV_INS_RFLAG_WTM);
159518781Sgibbs	if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) == 0) {
159618781Sgibbs		return (0);
159718781Sgibbs	}
159818781Sgibbs	return (1);
159918781Sgibbs}
160018781Sgibbs
160139217Sgibbsstatic int
160239217Sgibbsadv_host_req_chip_halt(struct adv_softc *adv)
160339217Sgibbs{
160439217Sgibbs	int	 count;
160539217Sgibbs	u_int8_t saved_stop_code;
160639217Sgibbs
160739217Sgibbs	if (adv_is_chip_halted(adv))
160839217Sgibbs		return (1);
160939217Sgibbs
161039217Sgibbs	count = 0;
161139217Sgibbs	saved_stop_code = adv_read_lram_8(adv, ADVV_STOP_CODE_B);
161239217Sgibbs	adv_write_lram_8(adv, ADVV_STOP_CODE_B,
161339217Sgibbs			 ADV_STOP_HOST_REQ_RISC_HALT | ADV_STOP_REQ_RISC_STOP);
161439217Sgibbs	while (adv_is_chip_halted(adv) == 0
161539217Sgibbs	    && count++ < 2000)
161639217Sgibbs		;
161739217Sgibbs
161839217Sgibbs	adv_write_lram_8(adv, ADVV_STOP_CODE_B, saved_stop_code);
161939217Sgibbs	return (count < 2000);
162039217Sgibbs}
162139217Sgibbs
162218781Sgibbsstatic void
162339217Sgibbsadv_set_chip_ih(struct adv_softc *adv, u_int16_t ins_code)
162418781Sgibbs{
162518781Sgibbs	adv_set_bank(adv, 1);
162618781Sgibbs	ADV_OUTW(adv, ADV_REG_IH, ins_code);
162718781Sgibbs	adv_set_bank(adv, 0);
162818781Sgibbs}
162918781Sgibbs
1630153072Sru#if 0
163118781Sgibbsstatic u_int8_t
163239217Sgibbsadv_get_chip_scsi_ctrl(struct adv_softc *adv)
163318781Sgibbs{
163418781Sgibbs	u_int8_t scsi_ctrl;
163518781Sgibbs
163618781Sgibbs	adv_set_bank(adv, 1);
163718781Sgibbs	scsi_ctrl = ADV_INB(adv, ADV_REG_SC);
163818781Sgibbs	adv_set_bank(adv, 0);
163918781Sgibbs	return (scsi_ctrl);
164018781Sgibbs}
164118781Sgibbs#endif
164218781Sgibbs
164318781Sgibbs/*
164418781Sgibbs * XXX Looks like more padding issues in this routine as well.
164518781Sgibbs *     There has to be a way to turn this into an insw.
164618781Sgibbs */
164718781Sgibbsstatic void
164839217Sgibbsadv_get_q_info(struct adv_softc *adv, u_int16_t s_addr,
164939217Sgibbs	       u_int16_t *inbuf, int words)
165018781Sgibbs{
165118781Sgibbs	int	i;
165218781Sgibbs
165318781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
165418781Sgibbs	for (i = 0; i < words; i++, inbuf++) {
165518781Sgibbs		if (i == 5) {
165618781Sgibbs			continue;
165718781Sgibbs		}
165818781Sgibbs		*inbuf = ADV_INW(adv, ADV_LRAM_DATA);
165918781Sgibbs	}
166018781Sgibbs}
166118781Sgibbs
166218781Sgibbsstatic u_int
166339217Sgibbsadv_get_num_free_queues(struct adv_softc *adv, u_int8_t n_qs)
166418781Sgibbs{
166518781Sgibbs	u_int	  cur_used_qs;
166618781Sgibbs	u_int	  cur_free_qs;
166718781Sgibbs
166839217Sgibbs	cur_used_qs = adv->cur_active + ADV_MIN_FREE_Q;
166918781Sgibbs
167018781Sgibbs	if ((cur_used_qs + n_qs) <= adv->max_openings) {
167118781Sgibbs		cur_free_qs = adv->max_openings - cur_used_qs;
167218781Sgibbs		return (cur_free_qs);
167318781Sgibbs	}
167439217Sgibbs	adv->openings_needed = n_qs;
167518781Sgibbs	return (0);
167618781Sgibbs}
167718781Sgibbs
167818781Sgibbsstatic u_int8_t
167939217Sgibbsadv_alloc_free_queues(struct adv_softc *adv, u_int8_t free_q_head,
168039217Sgibbs		      u_int8_t n_free_q)
168118781Sgibbs{
168218781Sgibbs	int i;
168318781Sgibbs
168418781Sgibbs	for (i = 0; i < n_free_q; i++) {
168518781Sgibbs		free_q_head = adv_alloc_free_queue(adv, free_q_head);
168618781Sgibbs		if (free_q_head == ADV_QLINK_END)
168718781Sgibbs			break;
168818781Sgibbs	}
168918781Sgibbs	return (free_q_head);
169018781Sgibbs}
169118781Sgibbs
169218781Sgibbsstatic u_int8_t
169339217Sgibbsadv_alloc_free_queue(struct adv_softc *adv, u_int8_t free_q_head)
169418781Sgibbs{
169518781Sgibbs	u_int16_t	q_addr;
169618781Sgibbs	u_int8_t	next_qp;
169718781Sgibbs	u_int8_t	q_status;
169818781Sgibbs
169918781Sgibbs	next_qp = ADV_QLINK_END;
170018781Sgibbs	q_addr = ADV_QNO_TO_QADDR(free_q_head);
170118781Sgibbs	q_status = adv_read_lram_8(adv,	q_addr + ADV_SCSIQ_B_STATUS);
170218781Sgibbs
170318781Sgibbs	if ((q_status & QS_READY) == 0)
170418781Sgibbs		next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD);
170518781Sgibbs
170618781Sgibbs	return (next_qp);
170718781Sgibbs}
170818781Sgibbs
170918781Sgibbsstatic int
171039217Sgibbsadv_send_scsi_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq,
171139217Sgibbs		    u_int8_t n_q_required)
171218781Sgibbs{
171318781Sgibbs	u_int8_t	free_q_head;
171418781Sgibbs	u_int8_t	next_qp;
171518781Sgibbs	int		retval;
171618781Sgibbs
171718781Sgibbs	retval = 1;
171818781Sgibbs	free_q_head = adv_read_lram_16(adv, ADVV_FREE_Q_HEAD_W) & 0xFF;
171918781Sgibbs	if ((next_qp = adv_alloc_free_queues(adv, free_q_head, n_q_required))
172018781Sgibbs	    != ADV_QLINK_END) {
172118781Sgibbs		scsiq->q1.q_no = free_q_head;
172218781Sgibbs
172318781Sgibbs		/*
172418781Sgibbs		 * Now that we know our Q number, point our sense
172539217Sgibbs		 * buffer pointer to a bus dma mapped area where
172639217Sgibbs		 * we can dma the data to.
172718781Sgibbs		 */
172839217Sgibbs		scsiq->q1.sense_addr = adv->sense_physbase
172939217Sgibbs		    + ((free_q_head - 1) * sizeof(struct scsi_sense_data));
173018781Sgibbs		adv_put_ready_sg_list_queue(adv, scsiq, free_q_head);
173118781Sgibbs		adv_write_lram_16(adv, ADVV_FREE_Q_HEAD_W, next_qp);
173218781Sgibbs		adv->cur_active += n_q_required;
173318781Sgibbs		retval = 0;
173418781Sgibbs	}
173518781Sgibbs	return (retval);
173618781Sgibbs}
173718781Sgibbs
173818781Sgibbs
173918781Sgibbsstatic void
174039217Sgibbsadv_put_ready_sg_list_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq,
174139217Sgibbs			    u_int q_no)
174218781Sgibbs{
174318781Sgibbs	u_int8_t	sg_list_dwords;
174418781Sgibbs	u_int8_t	sg_index, i;
174518781Sgibbs	u_int8_t	sg_entry_cnt;
174618781Sgibbs	u_int8_t	next_qp;
174718781Sgibbs	u_int16_t	q_addr;
174818781Sgibbs	struct		adv_sg_head *sg_head;
174918781Sgibbs	struct		adv_sg_list_q scsi_sg_q;
175018781Sgibbs
175118781Sgibbs	sg_head = scsiq->sg_head;
175218781Sgibbs
175318781Sgibbs	if (sg_head) {
175418781Sgibbs		sg_entry_cnt = sg_head->entry_cnt - 1;
175518781Sgibbs#ifdef DIAGNOSTIC
175618781Sgibbs		if (sg_entry_cnt == 0)
175739217Sgibbs			panic("adv_put_ready_sg_list_queue: ScsiQ with "
175839217Sgibbs			      "a SG list but only one element");
175918781Sgibbs		if ((scsiq->q1.cntl & QC_SG_HEAD) == 0)
176039217Sgibbs			panic("adv_put_ready_sg_list_queue: ScsiQ with "
176139217Sgibbs			      "a SG list but QC_SG_HEAD not set");
176218781Sgibbs#endif
176318781Sgibbs		q_addr = ADV_QNO_TO_QADDR(q_no);
176418781Sgibbs		sg_index = 1;
176518781Sgibbs		scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
176618781Sgibbs		scsi_sg_q.sg_head_qp = q_no;
176718781Sgibbs		scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
176818781Sgibbs		for (i = 0; i < sg_head->queue_cnt; i++) {
176918781Sgibbs			u_int8_t segs_this_q;
177018781Sgibbs
177118781Sgibbs			if (sg_entry_cnt > ADV_SG_LIST_PER_Q)
177218781Sgibbs				segs_this_q = ADV_SG_LIST_PER_Q;
177318781Sgibbs			else {
177418781Sgibbs				/* This will be the last segment then */
177518781Sgibbs				segs_this_q = sg_entry_cnt;
177618781Sgibbs				scsi_sg_q.cntl |= QCSG_SG_XFER_END;
177718781Sgibbs			}
177818781Sgibbs			scsi_sg_q.seq_no = i + 1;
177939217Sgibbs			sg_list_dwords = segs_this_q << 1;
178018781Sgibbs			if (i == 0) {
178118781Sgibbs				scsi_sg_q.sg_list_cnt = segs_this_q;
178218781Sgibbs				scsi_sg_q.sg_cur_list_cnt = segs_this_q;
178318781Sgibbs			} else {
178418781Sgibbs				scsi_sg_q.sg_list_cnt = segs_this_q - 1;
178518781Sgibbs				scsi_sg_q.sg_cur_list_cnt = segs_this_q - 1;
178618781Sgibbs			}
178718781Sgibbs			next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD);
178818781Sgibbs			scsi_sg_q.q_no = next_qp;
178918781Sgibbs			q_addr = ADV_QNO_TO_QADDR(next_qp);
179018781Sgibbs
179139217Sgibbs			adv_write_lram_16_multi(adv,
179239217Sgibbs						q_addr + ADV_SCSIQ_SGHD_CPY_BEG,
179318781Sgibbs						(u_int16_t *)&scsi_sg_q,
179418781Sgibbs						sizeof(scsi_sg_q) >> 1);
179518781Sgibbs			adv_write_lram_32_multi(adv, q_addr + ADV_SGQ_LIST_BEG,
179618781Sgibbs						(u_int32_t *)&sg_head->sg_list[sg_index],
179718781Sgibbs						sg_list_dwords);
179818781Sgibbs			sg_entry_cnt -= segs_this_q;
179918781Sgibbs			sg_index += ADV_SG_LIST_PER_Q;
180018781Sgibbs		}
180118781Sgibbs	}
180218781Sgibbs	adv_put_ready_queue(adv, scsiq, q_no);
180318781Sgibbs}
180418781Sgibbs
180518781Sgibbsstatic void
180639217Sgibbsadv_put_ready_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq,
180739217Sgibbs		    u_int q_no)
180818781Sgibbs{
180939217Sgibbs	struct		adv_target_transinfo* tinfo;
181039217Sgibbs	u_int		q_addr;
181139217Sgibbs	u_int		tid_no;
181218781Sgibbs
181339217Sgibbs	tid_no = ADV_TIX_TO_TID(scsiq->q2.target_ix);
181439217Sgibbs	tinfo = &adv->tinfo[tid_no];
181546581Sken	if ((tinfo->current.period != tinfo->goal.period)
181646581Sken	 || (tinfo->current.offset != tinfo->goal.offset)) {
181718781Sgibbs
181839217Sgibbs		adv_msgout_sdtr(adv, tinfo->goal.period, tinfo->goal.offset);
181918781Sgibbs		scsiq->q1.cntl |= QC_MSG_OUT;
182018781Sgibbs	}
182118781Sgibbs	q_addr = ADV_QNO_TO_QADDR(q_no);
182218781Sgibbs
182318781Sgibbs	scsiq->q1.status = QS_FREE;
182418781Sgibbs
182518781Sgibbs	adv_write_lram_16_multi(adv, q_addr + ADV_SCSIQ_CDB_BEG,
182618781Sgibbs				(u_int16_t *)scsiq->cdbptr,
182718781Sgibbs				scsiq->q2.cdb_len >> 1);
182818781Sgibbs
182918781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
183018781Sgibbs	adv_adj_scsiq_endian(scsiq);
183118781Sgibbs#endif
183218781Sgibbs
183318781Sgibbs	adv_put_scsiq(adv, q_addr + ADV_SCSIQ_CPY_BEG,
183418781Sgibbs		      (u_int16_t *) &scsiq->q1.cntl,
183518781Sgibbs		      ((sizeof(scsiq->q1) + sizeof(scsiq->q2)) / 2) - 1);
183618781Sgibbs
1837153072Sru#ifdef CC_WRITE_IO_COUNT
183818781Sgibbs	adv_write_lram_16(adv, q_addr + ADV_SCSIQ_W_REQ_COUNT,
183918781Sgibbs			  adv->req_count);
184018781Sgibbs#endif
184118781Sgibbs
1842153072Sru#ifdef CC_CLEAR_DMA_REMAIN
184318781Sgibbs
184418781Sgibbs	adv_write_lram_32(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_ADDR, 0);
184518781Sgibbs	adv_write_lram_32(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_CNT, 0);
184618781Sgibbs#endif
184718781Sgibbs
184818781Sgibbs	adv_write_lram_16(adv, q_addr + ADV_SCSIQ_B_STATUS,
184918781Sgibbs			  (scsiq->q1.q_no << 8) | QS_READY);
185018781Sgibbs}
185118781Sgibbs
185218781Sgibbsstatic void
185339217Sgibbsadv_put_scsiq(struct adv_softc *adv, u_int16_t s_addr,
185439217Sgibbs	      u_int16_t *buffer, int words)
185518781Sgibbs{
185618781Sgibbs	int	i;
185718781Sgibbs
185818781Sgibbs	/*
185918781Sgibbs	 * XXX This routine makes *gross* assumptions
186018781Sgibbs	 * about padding in the data structures.
186118781Sgibbs	 * Either the data structures should have explicit
186218781Sgibbs	 * padding members added, or they should have padding
186318781Sgibbs	 * turned off via compiler attributes depending on
186418781Sgibbs	 * which yields better overall performance.  My hunch
186518781Sgibbs	 * would be that turning off padding would be the
186618781Sgibbs	 * faster approach as an outsw is much faster than
186718781Sgibbs	 * this crude loop and accessing un-aligned data
186818781Sgibbs	 * members isn't *that* expensive.  The other choice
186918781Sgibbs	 * would be to modify the ASC script so that the
187018781Sgibbs	 * the adv_scsiq_1 structure can be re-arranged so
187118781Sgibbs	 * padding isn't required.
187218781Sgibbs	 */
187318781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
187418781Sgibbs	for (i = 0; i < words; i++, buffer++) {
187518781Sgibbs		if (i == 2 || i == 10) {
187618781Sgibbs			continue;
187718781Sgibbs		}
187818781Sgibbs		ADV_OUTW(adv, ADV_LRAM_DATA, *buffer);
187918781Sgibbs	}
188018781Sgibbs}
188118781Sgibbs
1882111342Sobrien#if BYTE_ORDER == BIG_ENDIAN
1883111342Sobrienvoid
1884111342Sobrienadv_adj_endian_qdone_info(struct adv_q_done_info *scsiq)
1885111342Sobrien{
1886111342Sobrien
1887111342Sobrien	panic("adv(4) not supported on big-endian machines.\n");
1888111342Sobrien}
1889111342Sobrien
1890111342Sobrienvoid
1891111342Sobrienadv_adj_scsiq_endian(struct adv_scsi_q *scsiq)
1892111342Sobrien{
1893111342Sobrien
1894111342Sobrien	panic("adv(4) not supported on big-endian machines.\n");
1895111342Sobrien}
1896111342Sobrien#endif
1897111342Sobrien
189839217Sgibbsstatic void
189939217Sgibbsadv_handle_extmsg_in(struct adv_softc *adv, u_int16_t halt_q_addr,
190039217Sgibbs		     u_int8_t q_cntl, target_bit_vector target_mask,
190139217Sgibbs		     int tid_no)
190218781Sgibbs{
190339217Sgibbs	struct	ext_msg ext_msg;
190418781Sgibbs
190539217Sgibbs	adv_read_lram_16_multi(adv, ADVV_MSGIN_BEG, (u_int16_t *) &ext_msg,
190639217Sgibbs			       sizeof(ext_msg) >> 1);
190739217Sgibbs	if ((ext_msg.msg_type == MSG_EXTENDED)
190839217Sgibbs	 && (ext_msg.msg_req == MSG_EXT_SDTR)
190939217Sgibbs	 && (ext_msg.msg_len == MSG_EXT_SDTR_LEN)) {
191055945Sgibbs		union	  ccb *ccb;
191155945Sgibbs		struct	  adv_target_transinfo* tinfo;
191255945Sgibbs		u_int32_t cinfo_index;
191339217Sgibbs		u_int	 period;
191439217Sgibbs		u_int	 offset;
191539217Sgibbs		int	 sdtr_accept;
191639217Sgibbs		u_int8_t orig_offset;
191739217Sgibbs
191855945Sgibbs		cinfo_index =
191955945Sgibbs		    adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX);
192055945Sgibbs		ccb = adv->ccb_infos[cinfo_index].ccb;
192139217Sgibbs		tinfo = &adv->tinfo[tid_no];
192239217Sgibbs		sdtr_accept = TRUE;
192339217Sgibbs
192439217Sgibbs		orig_offset = ext_msg.req_ack_offset;
192539217Sgibbs		if (ext_msg.xfer_period < tinfo->goal.period) {
192639217Sgibbs                	sdtr_accept = FALSE;
192739217Sgibbs			ext_msg.xfer_period = tinfo->goal.period;
192839217Sgibbs		}
192939217Sgibbs
193039217Sgibbs		/* Perform range checking */
193139217Sgibbs		period = ext_msg.xfer_period;
193239217Sgibbs		offset = ext_msg.req_ack_offset;
193339217Sgibbs		adv_period_offset_to_sdtr(adv, &period,  &offset, tid_no);
193439217Sgibbs		ext_msg.xfer_period = period;
193539217Sgibbs		ext_msg.req_ack_offset = offset;
193639217Sgibbs
193739217Sgibbs		/* Record our current sync settings */
193839217Sgibbs		adv_set_syncrate(adv, ccb->ccb_h.path,
193939217Sgibbs				 tid_no, ext_msg.xfer_period,
194039217Sgibbs				 ext_msg.req_ack_offset,
194139217Sgibbs				 ADV_TRANS_GOAL|ADV_TRANS_ACTIVE);
194239217Sgibbs
194339217Sgibbs		/* Offset too high or large period forced async */
194439217Sgibbs		if (orig_offset != ext_msg.req_ack_offset)
194539217Sgibbs			sdtr_accept = FALSE;
194639217Sgibbs
194739217Sgibbs		if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
194839217Sgibbs			/* Valid response to our requested negotiation */
194939217Sgibbs			q_cntl &= ~QC_MSG_OUT;
195039217Sgibbs		} else {
195139217Sgibbs			/* Must Respond */
195239217Sgibbs			q_cntl |= QC_MSG_OUT;
195339217Sgibbs			adv_msgout_sdtr(adv, ext_msg.xfer_period,
195439217Sgibbs					ext_msg.req_ack_offset);
195539217Sgibbs		}
195639217Sgibbs
195739217Sgibbs	} else if (ext_msg.msg_type == MSG_EXTENDED
195839217Sgibbs		&& ext_msg.msg_req == MSG_EXT_WDTR
195939217Sgibbs		&& ext_msg.msg_len == MSG_EXT_WDTR_LEN) {
196039217Sgibbs
196139217Sgibbs		ext_msg.wdtr_width = 0;
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        } else {
196739217Sgibbs
196839217Sgibbs		ext_msg.msg_type = MSG_MESSAGE_REJECT;
196939217Sgibbs		adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG,
197039217Sgibbs					(u_int16_t *)&ext_msg,
197139217Sgibbs					sizeof(ext_msg) >> 1);
197239217Sgibbs		q_cntl |= QC_MSG_OUT;
197339217Sgibbs        }
197439217Sgibbs	adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl);
197539217Sgibbs}
197639217Sgibbs
197739217Sgibbsstatic void
197839217Sgibbsadv_msgout_sdtr(struct adv_softc *adv, u_int8_t sdtr_period,
197939217Sgibbs		u_int8_t sdtr_offset)
198039217Sgibbs{
198139217Sgibbs	struct	 ext_msg sdtr_buf;
198239217Sgibbs
198318781Sgibbs	sdtr_buf.msg_type = MSG_EXTENDED;
198418781Sgibbs	sdtr_buf.msg_len = MSG_EXT_SDTR_LEN;
198518781Sgibbs	sdtr_buf.msg_req = MSG_EXT_SDTR;
198618781Sgibbs	sdtr_buf.xfer_period = sdtr_period;
198718781Sgibbs	sdtr_offset &= ADV_SYN_MAX_OFFSET;
198818781Sgibbs	sdtr_buf.req_ack_offset = sdtr_offset;
198918781Sgibbs	adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG,
199018781Sgibbs				(u_int16_t *) &sdtr_buf,
199118781Sgibbs				sizeof(sdtr_buf) / 2);
199218781Sgibbs}
199318781Sgibbs
199439217Sgibbsint
199539217Sgibbsadv_abort_ccb(struct adv_softc *adv, int target, int lun, union ccb *ccb,
199639217Sgibbs	      u_int32_t status, int queued_only)
199718781Sgibbs{
199839217Sgibbs	u_int16_t q_addr;
199939217Sgibbs	u_int8_t  q_no;
200039217Sgibbs	struct adv_q_done_info scsiq_buf;
200139217Sgibbs	struct adv_q_done_info *scsiq;
200239217Sgibbs	u_int8_t  target_ix;
200339217Sgibbs	int	  count;
200418781Sgibbs
2005241492Sjhb	if (!dumping)
2006241492Sjhb		mtx_assert(&adv->lock, MA_OWNED);
200739217Sgibbs	scsiq = &scsiq_buf;
200839217Sgibbs	target_ix = ADV_TIDLUN_TO_IX(target, lun);
200939217Sgibbs	count = 0;
201039217Sgibbs	for (q_no = ADV_MIN_ACTIVE_QNO; q_no <= adv->max_openings; q_no++) {
201155945Sgibbs		struct adv_ccb_info *ccb_info;
201239217Sgibbs		q_addr = ADV_QNO_TO_QADDR(q_no);
201339217Sgibbs
201439217Sgibbs		adv_copy_lram_doneq(adv, q_addr, scsiq, adv->max_dma_count);
201555945Sgibbs		ccb_info = &adv->ccb_infos[scsiq->d2.ccb_index];
201639217Sgibbs		if (((scsiq->q_status & QS_READY) != 0)
201739217Sgibbs		 && ((scsiq->q_status & QS_ABORTED) == 0)
201839217Sgibbs		 && ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)
201939217Sgibbs		 && (scsiq->d2.target_ix == target_ix)
202039217Sgibbs		 && (queued_only == 0
202139217Sgibbs		  || !(scsiq->q_status & (QS_DISC1|QS_DISC2|QS_BUSY|QS_DONE)))
202255945Sgibbs		 && (ccb == NULL || (ccb == ccb_info->ccb))) {
202339217Sgibbs			union ccb *aborted_ccb;
202439217Sgibbs			struct adv_ccb_info *cinfo;
202539217Sgibbs
202639217Sgibbs			scsiq->q_status |= QS_ABORTED;
202739217Sgibbs			adv_write_lram_8(adv, q_addr + ADV_SCSIQ_B_STATUS,
202839217Sgibbs					 scsiq->q_status);
202955945Sgibbs			aborted_ccb = ccb_info->ccb;
203039217Sgibbs			/* Don't clobber earlier error codes */
203139217Sgibbs			if ((aborted_ccb->ccb_h.status & CAM_STATUS_MASK)
203239217Sgibbs			  == CAM_REQ_INPROG)
203339217Sgibbs				aborted_ccb->ccb_h.status |= status;
203439217Sgibbs			cinfo = (struct adv_ccb_info *)
203539217Sgibbs			    aborted_ccb->ccb_h.ccb_cinfo_ptr;
203639217Sgibbs			cinfo->state |= ACCB_ABORT_QUEUED;
203739217Sgibbs			count++;
203818781Sgibbs		}
203918781Sgibbs	}
204039217Sgibbs	return (count);
204118781Sgibbs}
204218781Sgibbs
204339217Sgibbsint
204455945Sgibbsadv_reset_bus(struct adv_softc *adv, int initiate_bus_reset)
204539217Sgibbs{
204639217Sgibbs	int count;
204739217Sgibbs	int i;
204839217Sgibbs	union ccb *ccb;
204939217Sgibbs
2050241492Sjhb	if (!dumping)
2051241492Sjhb		mtx_assert(&adv->lock, MA_OWNED);
205255945Sgibbs	i = 200;
205355945Sgibbs	while ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_SCSI_RESET_ACTIVE) != 0
205455945Sgibbs	    && i--)
205555945Sgibbs		DELAY(1000);
205655945Sgibbs	adv_reset_chip(adv, initiate_bus_reset);
205739217Sgibbs	adv_reinit_lram(adv);
205855945Sgibbs	for (i = 0; i <= ADV_MAX_TID; i++)
205955945Sgibbs		adv_set_syncrate(adv, NULL, i, /*period*/0,
206055945Sgibbs				 /*offset*/0, ADV_TRANS_CUR);
206139217Sgibbs	ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR);
206239217Sgibbs
2063298955Spfg	/* Tell the XPT layer that a bus reset occurred */
206439217Sgibbs	if (adv->path != NULL)
206539217Sgibbs		xpt_async(AC_BUS_RESET, adv->path, NULL);
206639217Sgibbs
206739217Sgibbs	count = 0;
206839217Sgibbs	while ((ccb = (union ccb *)LIST_FIRST(&adv->pending_ccbs)) != NULL) {
206939217Sgibbs		if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG)
207039217Sgibbs			ccb->ccb_h.status |= CAM_SCSI_BUS_RESET;
207139217Sgibbs		adv_done(adv, ccb, QD_ABORTED_BY_HOST, 0, 0, 0);
207239217Sgibbs		count++;
207339217Sgibbs	}
207439217Sgibbs
207539217Sgibbs	adv_start_chip(adv);
207639217Sgibbs	return (count);
207739217Sgibbs}
207839217Sgibbs
207918781Sgibbsstatic void
208039217Sgibbsadv_set_sdtr_reg_at_id(struct adv_softc *adv, int tid, u_int8_t sdtr_data)
208118781Sgibbs{
208239217Sgibbs	int orig_id;
208339217Sgibbs
208439217Sgibbs    	adv_set_bank(adv, 1);
208539217Sgibbs    	orig_id = ffs(ADV_INB(adv, ADV_HOST_SCSIID)) - 1;
208639217Sgibbs    	ADV_OUTB(adv, ADV_HOST_SCSIID, tid);
208739217Sgibbs	if (ADV_INB(adv, ADV_HOST_SCSIID) == (0x01 << tid)) {
208839217Sgibbs		adv_set_bank(adv, 0);
208939217Sgibbs		ADV_OUTB(adv, ADV_SYN_OFFSET, sdtr_data);
209039217Sgibbs	}
209139217Sgibbs    	adv_set_bank(adv, 1);
209239217Sgibbs    	ADV_OUTB(adv, ADV_HOST_SCSIID, orig_id);
209339217Sgibbs	adv_set_bank(adv, 0);
209418781Sgibbs}
2095