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>
48251164Sscottl#include <sys/conf.h>
49251164Sscottl#include <sys/lock.h>
5045846Sgibbs#include <sys/kernel.h>
51251164Sscottl#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;
304251164Sscottl	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
31939217Sgibbs		num_entries = sizeof(adv_quirk_table)/sizeof(*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
467251164Sscottladv_find_signature(struct resource *res)
46839217Sgibbs{
46939217Sgibbs	u_int16_t signature;
47039217Sgibbs
471251164Sscottl	if (bus_read_1(res, ADV_SIGNATURE_BYTE) == ADV_1000_ID1B) {
472251164Sscottl		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) {
601251164Sscottl		device_printf(adv->dev,
602251164Sscottl		    "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
699251164Sscottl	if (!dumping)
700251164Sscottl		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
947251164Sscottl	if (!dumping)
948251164Sscottl		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;
977251164Sscottl		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);
1020251164Sscottl		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		 */
1034251164Sscottl		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		u_int8_t scsi_status;
105539217Sgibbs		union ccb *ccb;
105655945Sgibbs		u_int32_t cinfo_index;
105739217Sgibbs
105839217Sgibbs		scsi_status = adv_read_lram_8(adv, halt_q_addr
105939217Sgibbs					      + ADV_SCSIQ_SCSI_STATUS);
106055945Sgibbs		cinfo_index =
106155945Sgibbs		    adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX);
106255945Sgibbs		ccb = adv->ccb_infos[cinfo_index].ccb;
106339217Sgibbs		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
106440733Sgibbs		ccb->ccb_h.status |= CAM_DEV_QFRZN|CAM_SCSI_STATUS_ERROR;
106540733Sgibbs		ccb->csio.scsi_status = SCSI_STATUS_QUEUE_FULL;
106639217Sgibbs		adv_abort_ccb(adv, tid_no, ADV_TIX_TO_LUN(target_ix),
106739217Sgibbs			      /*ccb*/NULL, CAM_REQUEUE_REQ,
106839217Sgibbs			      /*queued_only*/TRUE);
106939217Sgibbs		scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B);
107039217Sgibbs		scsi_busy &= ~target_mask;
107139217Sgibbs		adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy);
107255945Sgibbs	} else {
107355945Sgibbs		printf("Unhandled Halt Code %x\n", int_halt_code);
107439217Sgibbs	}
107539217Sgibbs	adv_write_lram_16(adv, ADVV_HALTCODE_W, 0);
107639217Sgibbs}
107718781Sgibbs
107839217Sgibbsvoid
107939217Sgibbsadv_sdtr_to_period_offset(struct adv_softc *adv,
108039217Sgibbs			  u_int8_t sync_data, u_int8_t *period,
108139217Sgibbs			  u_int8_t *offset, int tid)
108239217Sgibbs{
108339217Sgibbs	if (adv->fix_asyn_xfer & ADV_TID_TO_TARGET_MASK(tid)
108439217Sgibbs	 && (sync_data == ASYN_SDTR_DATA_FIX_PCI_REV_AB)) {
108539217Sgibbs		*period = *offset = 0;
108639217Sgibbs	} else {
108739217Sgibbs		*period = adv->sdtr_period_tbl[((sync_data >> 4) & 0xF)];
108839217Sgibbs		*offset = sync_data & 0xF;
108939217Sgibbs	}
109039217Sgibbs}
109139217Sgibbs
109239217Sgibbsvoid
109339217Sgibbsadv_set_syncrate(struct adv_softc *adv, struct cam_path *path,
109439217Sgibbs		 u_int tid, u_int period, u_int offset, u_int type)
109539217Sgibbs{
109639217Sgibbs	struct adv_target_transinfo* tinfo;
109739217Sgibbs	u_int old_period;
109839217Sgibbs	u_int old_offset;
109939217Sgibbs	u_int8_t sdtr_data;
110039217Sgibbs
1101251164Sscottl	mtx_assert(&adv->lock, MA_OWNED);
110239217Sgibbs	tinfo = &adv->tinfo[tid];
110339217Sgibbs
110439217Sgibbs	/* Filter our input */
110539217Sgibbs	sdtr_data = adv_period_offset_to_sdtr(adv, &period,
110639217Sgibbs					      &offset, tid);
110739217Sgibbs
110839217Sgibbs	old_period = tinfo->current.period;
110939217Sgibbs	old_offset = tinfo->current.offset;
111039217Sgibbs
111139217Sgibbs	if ((type & ADV_TRANS_CUR) != 0
111239217Sgibbs	 && ((old_period != period || old_offset != offset)
111339217Sgibbs	  || period == 0 || offset == 0) /*Changes in asyn fix settings*/) {
111439217Sgibbs		int halted;
111539217Sgibbs
111639217Sgibbs		halted = adv_is_chip_halted(adv);
111739217Sgibbs		if (halted == 0)
111839217Sgibbs			/* Must halt the chip first */
111939217Sgibbs			adv_host_req_chip_halt(adv);
112039217Sgibbs
112139217Sgibbs		/* Update current hardware settings */
112239217Sgibbs		adv_set_sdtr_reg_at_id(adv, tid, sdtr_data);
112339217Sgibbs
112418781Sgibbs		/*
112539217Sgibbs		 * If a target can run in sync mode, we don't need
112639217Sgibbs		 * to check it for sync problems.
112718781Sgibbs		 */
112839217Sgibbs		if (offset != 0)
112939217Sgibbs			adv->fix_asyn_xfer &= ~ADV_TID_TO_TARGET_MASK(tid);
113018781Sgibbs
113139217Sgibbs		if (halted == 0)
113239217Sgibbs			/* Start the chip again */
113339217Sgibbs			adv_start_chip(adv);
113418781Sgibbs
113539217Sgibbs		tinfo->current.period = period;
113639217Sgibbs		tinfo->current.offset = offset;
113739217Sgibbs
113839217Sgibbs		if (path != NULL) {
113939217Sgibbs			/*
114039217Sgibbs			 * Tell the SCSI layer about the
114139217Sgibbs			 * new transfer parameters.
114239217Sgibbs			 */
114339217Sgibbs			struct	ccb_trans_settings neg;
1144163816Smjacob			memset(&neg, 0, sizeof (neg));
1145163816Smjacob			struct ccb_trans_settings_spi *spi =
1146163816Smjacob			    &neg.xport_specific.spi;
114739217Sgibbs
1148163816Smjacob			neg.protocol = PROTO_SCSI;
1149163816Smjacob			neg.protocol_version = SCSI_REV_2;
1150163816Smjacob			neg.transport = XPORT_SPI;
1151163816Smjacob			neg.transport_version = 2;
1152163816Smjacob
1153163816Smjacob			spi->sync_offset = offset;
1154163816Smjacob			spi->sync_period = period;
1155163816Smjacob			spi->valid |= CTS_SPI_VALID_SYNC_OFFSET;
1156163816Smjacob			spi->valid |= CTS_SPI_VALID_SYNC_RATE;
115739217Sgibbs			xpt_setup_ccb(&neg.ccb_h, path, /*priority*/1);
115839217Sgibbs			xpt_async(AC_TRANSFER_NEG, path, &neg);
115939217Sgibbs		}
116039217Sgibbs	}
116139217Sgibbs
116239217Sgibbs	if ((type & ADV_TRANS_GOAL) != 0) {
116339217Sgibbs		tinfo->goal.period = period;
116439217Sgibbs		tinfo->goal.offset = offset;
116539217Sgibbs	}
116639217Sgibbs
116739217Sgibbs	if ((type & ADV_TRANS_USER) != 0) {
116839217Sgibbs		tinfo->user.period = period;
116939217Sgibbs		tinfo->user.offset = offset;
117039217Sgibbs	}
117139217Sgibbs}
117239217Sgibbs
117339217Sgibbsu_int8_t
117439217Sgibbsadv_period_offset_to_sdtr(struct adv_softc *adv, u_int *period,
117539217Sgibbs			  u_int *offset, int tid)
117639217Sgibbs{
117739217Sgibbs	u_int i;
117839217Sgibbs	u_int dummy_offset;
117939217Sgibbs	u_int dummy_period;
118039217Sgibbs
118139217Sgibbs	if (offset == NULL) {
118239217Sgibbs		dummy_offset = 0;
118339217Sgibbs		offset = &dummy_offset;
118439217Sgibbs	}
118539217Sgibbs
118639217Sgibbs	if (period == NULL) {
118739217Sgibbs		dummy_period = 0;
118839217Sgibbs		period = &dummy_period;
118939217Sgibbs	}
119039217Sgibbs
119139217Sgibbs	*offset = MIN(ADV_SYN_MAX_OFFSET, *offset);
119239217Sgibbs	if (*period != 0 && *offset != 0) {
119339217Sgibbs		for (i = 0; i < adv->sdtr_period_tbl_size; i++) {
119439217Sgibbs			if (*period <= adv->sdtr_period_tbl[i]) {
119539217Sgibbs				/*
119639217Sgibbs				 * When responding to a target that requests
119739217Sgibbs				 * sync, the requested  rate may fall between
119839217Sgibbs				 * two rates that we can output, but still be
119939217Sgibbs				 * a rate that we can receive.  Because of this,
120039217Sgibbs				 * we want to respond to the target with
120139217Sgibbs				 * the same rate that it sent to us even
120239217Sgibbs				 * if the period we use to send data to it
120339217Sgibbs				 * is lower.  Only lower the response period
120439217Sgibbs				 * if we must.
120539217Sgibbs				 */
120639217Sgibbs				if (i == 0 /* Our maximum rate */)
120739217Sgibbs					*period = adv->sdtr_period_tbl[0];
120839217Sgibbs				return ((i << 4) | *offset);
120918781Sgibbs			}
121018781Sgibbs		}
121118781Sgibbs	}
121239217Sgibbs
121339217Sgibbs	/* Must go async */
121439217Sgibbs	*period = 0;
121539217Sgibbs	*offset = 0;
121639217Sgibbs	if (adv->fix_asyn_xfer & ADV_TID_TO_TARGET_MASK(tid))
121739217Sgibbs		return (ASYN_SDTR_DATA_FIX_PCI_REV_AB);
121839217Sgibbs	return (0);
121918781Sgibbs}
122018781Sgibbs
122118781Sgibbs/* Internal Routines */
122218781Sgibbs
122318781Sgibbsstatic void
122439217Sgibbsadv_read_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr,
122539217Sgibbs		       u_int16_t *buffer, int count)
122618781Sgibbs{
122718781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
122818781Sgibbs	ADV_INSW(adv, ADV_LRAM_DATA, buffer, count);
122918781Sgibbs}
123018781Sgibbs
123118781Sgibbsstatic void
123239217Sgibbsadv_write_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr,
123339217Sgibbs			u_int16_t *buffer, int count)
123418781Sgibbs{
123518781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
123618781Sgibbs	ADV_OUTSW(adv, ADV_LRAM_DATA, buffer, count);
123718781Sgibbs}
123818781Sgibbs
123918781Sgibbsstatic void
124039217Sgibbsadv_mset_lram_16(struct adv_softc *adv, u_int16_t s_addr,
124139217Sgibbs		 u_int16_t set_value, int count)
124218781Sgibbs{
124318781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
1244251164Sscottl	bus_set_multi_2(adv->res, adv->reg_off + ADV_LRAM_DATA,
1245251164Sscottl	    set_value, count);
124618781Sgibbs}
124718781Sgibbs
124818781Sgibbsstatic u_int32_t
124939217Sgibbsadv_msum_lram_16(struct adv_softc *adv, u_int16_t s_addr, int count)
125018781Sgibbs{
125118781Sgibbs	u_int32_t	sum;
125218781Sgibbs	int		i;
125318781Sgibbs
125418781Sgibbs	sum = 0;
125539217Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
125639217Sgibbs	for (i = 0; i < count; i++)
125739217Sgibbs		sum += ADV_INW(adv, ADV_LRAM_DATA);
125818781Sgibbs	return (sum);
125918781Sgibbs}
126018781Sgibbs
126118781Sgibbsstatic int
126239217Sgibbsadv_write_and_verify_lram_16(struct adv_softc *adv, u_int16_t addr,
126339217Sgibbs			     u_int16_t value)
126418781Sgibbs{
126518781Sgibbs	int	retval;
126618781Sgibbs
126718781Sgibbs	retval = 0;
126818781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
126918781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, value);
127039217Sgibbs	DELAY(10000);
127118781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
127218781Sgibbs	if (value != ADV_INW(adv, ADV_LRAM_DATA))
127318781Sgibbs		retval = 1;
127418781Sgibbs	return (retval);
127518781Sgibbs}
127618781Sgibbs
127718781Sgibbsstatic u_int32_t
127839217Sgibbsadv_read_lram_32(struct adv_softc *adv, u_int16_t addr)
127918781Sgibbs{
128018781Sgibbs	u_int16_t           val_low, val_high;
128118781Sgibbs
128218781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
128318781Sgibbs
128418781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
128518781Sgibbs	val_high = ADV_INW(adv, ADV_LRAM_DATA);
128618781Sgibbs	val_low = ADV_INW(adv, ADV_LRAM_DATA);
128718781Sgibbs#else
128818781Sgibbs	val_low = ADV_INW(adv, ADV_LRAM_DATA);
128918781Sgibbs	val_high = ADV_INW(adv, ADV_LRAM_DATA);
129018781Sgibbs#endif
129118781Sgibbs
129218781Sgibbs	return (((u_int32_t)val_high << 16) | (u_int32_t)val_low);
129318781Sgibbs}
129418781Sgibbs
129518781Sgibbsstatic void
129639217Sgibbsadv_write_lram_32(struct adv_softc *adv, u_int16_t addr, u_int32_t value)
129718781Sgibbs{
129818781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
129918781Sgibbs
130018781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
130118781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)((value >> 16) & 0xFFFF));
130218781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)(value & 0xFFFF));
130318781Sgibbs#else
130418781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)(value & 0xFFFF));
130518781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)((value >> 16) & 0xFFFF));
130618781Sgibbs#endif
130718781Sgibbs}
130818781Sgibbs
130918781Sgibbsstatic void
131039217Sgibbsadv_write_lram_32_multi(struct adv_softc *adv, u_int16_t s_addr,
131139217Sgibbs			u_int32_t *buffer, int count)
131218781Sgibbs{
131318781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
131439217Sgibbs	ADV_OUTSW(adv, ADV_LRAM_DATA, (u_int16_t *)buffer, count * 2);
131518781Sgibbs}
131618781Sgibbs
131718781Sgibbsstatic u_int16_t
131839217Sgibbsadv_read_eeprom_16(struct adv_softc *adv, u_int8_t addr)
131918781Sgibbs{
132018781Sgibbs	u_int16_t read_wval;
132118781Sgibbs	u_int8_t  cmd_reg;
132218781Sgibbs
132318781Sgibbs	adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_DISABLE);
132418781Sgibbs	DELAY(1000);
132518781Sgibbs	cmd_reg = addr | ADV_EEPROM_CMD_READ;
132618781Sgibbs	adv_write_eeprom_cmd_reg(adv, cmd_reg);
132718781Sgibbs	DELAY(1000);
132818781Sgibbs	read_wval = ADV_INW(adv, ADV_EEPROM_DATA);
132918781Sgibbs	DELAY(1000);
133018781Sgibbs	return (read_wval);
133118781Sgibbs}
133218781Sgibbs
133318781Sgibbsstatic u_int16_t
133439217Sgibbsadv_write_eeprom_16(struct adv_softc *adv, u_int8_t addr, u_int16_t value)
133518781Sgibbs{
133618781Sgibbs	u_int16_t	read_value;
133718781Sgibbs
133818781Sgibbs	read_value = adv_read_eeprom_16(adv, addr);
133918781Sgibbs	if (read_value != value) {
134018781Sgibbs		adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_ENABLE);
134118781Sgibbs		DELAY(1000);
134218781Sgibbs
134318781Sgibbs		ADV_OUTW(adv, ADV_EEPROM_DATA, value);
134418781Sgibbs		DELAY(1000);
134518781Sgibbs
134618781Sgibbs		adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE | addr);
134718781Sgibbs		DELAY(20 * 1000);
134818781Sgibbs
134918781Sgibbs		adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_DISABLE);
135018781Sgibbs		DELAY(1000);
135118781Sgibbs		read_value = adv_read_eeprom_16(adv, addr);
135218781Sgibbs	}
135318781Sgibbs	return (read_value);
135418781Sgibbs}
135518781Sgibbs
135618781Sgibbsstatic int
135739217Sgibbsadv_write_eeprom_cmd_reg(struct adv_softc *adv, u_int8_t cmd_reg)
135818781Sgibbs{
135918781Sgibbs	u_int8_t read_back;
136018781Sgibbs	int	 retry;
136118781Sgibbs
136218781Sgibbs	retry = 0;
136318781Sgibbs	while (1) {
136418781Sgibbs		ADV_OUTB(adv, ADV_EEPROM_CMD, cmd_reg);
136518781Sgibbs		DELAY(1000);
136618781Sgibbs		read_back = ADV_INB(adv, ADV_EEPROM_CMD);
136718781Sgibbs		if (read_back == cmd_reg) {
136818781Sgibbs			return (1);
136918781Sgibbs		}
137018781Sgibbs		if (retry++ > ADV_EEPROM_MAX_RETRY) {
137118781Sgibbs			return (0);
137218781Sgibbs		}
137318781Sgibbs	}
137418781Sgibbs}
137518781Sgibbs
137618781Sgibbsstatic int
137739217Sgibbsadv_set_eeprom_config_once(struct adv_softc *adv,
137839217Sgibbs			   struct adv_eeprom_config *eeprom_config)
137918781Sgibbs{
138018781Sgibbs	int		n_error;
138118781Sgibbs	u_int16_t	*wbuf;
138218781Sgibbs	u_int16_t	sum;
138318781Sgibbs	u_int8_t	s_addr;
138418781Sgibbs	u_int8_t	cfg_beg;
138518781Sgibbs	u_int8_t	cfg_end;
138618781Sgibbs
138718781Sgibbs	wbuf = (u_int16_t *)eeprom_config;
138818781Sgibbs	n_error = 0;
138918781Sgibbs	sum = 0;
139018781Sgibbs	for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
139118781Sgibbs		sum += *wbuf;
139218781Sgibbs		if (*wbuf != adv_write_eeprom_16(adv, s_addr, *wbuf)) {
139318781Sgibbs			n_error++;
139418781Sgibbs		}
139518781Sgibbs	}
139618781Sgibbs	if (adv->type & ADV_VL) {
139718781Sgibbs		cfg_beg = ADV_EEPROM_CFG_BEG_VL;
139818781Sgibbs		cfg_end = ADV_EEPROM_MAX_ADDR_VL;
139918781Sgibbs	} else {
140018781Sgibbs		cfg_beg = ADV_EEPROM_CFG_BEG;
140118781Sgibbs		cfg_end = ADV_EEPROM_MAX_ADDR;
140218781Sgibbs	}
140318781Sgibbs
140418781Sgibbs	for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
140518781Sgibbs		sum += *wbuf;
140618781Sgibbs		if (*wbuf != adv_write_eeprom_16(adv, s_addr, *wbuf)) {
140718781Sgibbs			n_error++;
140818781Sgibbs		}
140918781Sgibbs	}
141018781Sgibbs	*wbuf = sum;
141118781Sgibbs	if (sum != adv_write_eeprom_16(adv, s_addr, sum)) {
141218781Sgibbs		n_error++;
141318781Sgibbs	}
141418781Sgibbs	wbuf = (u_int16_t *)eeprom_config;
141518781Sgibbs	for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
141618781Sgibbs		if (*wbuf != adv_read_eeprom_16(adv, s_addr)) {
141718781Sgibbs			n_error++;
141818781Sgibbs		}
141918781Sgibbs	}
142018781Sgibbs	for (s_addr = cfg_beg; s_addr <= cfg_end; s_addr++, wbuf++) {
142118781Sgibbs		if (*wbuf != adv_read_eeprom_16(adv, s_addr)) {
142218781Sgibbs			n_error++;
142318781Sgibbs		}
142418781Sgibbs	}
142518781Sgibbs	return (n_error);
142618781Sgibbs}
142718781Sgibbs
142818781Sgibbsstatic u_int32_t
142939217Sgibbsadv_load_microcode(struct adv_softc *adv, u_int16_t s_addr,
143039217Sgibbs		   u_int16_t *mcode_buf, u_int16_t mcode_size)
143118781Sgibbs{
143239217Sgibbs	u_int32_t chksum;
143339217Sgibbs	u_int16_t mcode_lram_size;
143439217Sgibbs	u_int16_t mcode_chksum;
143518781Sgibbs
143618781Sgibbs	mcode_lram_size = mcode_size >> 1;
143718781Sgibbs	/* XXX Why zero the memory just before you write the whole thing?? */
143839217Sgibbs	adv_mset_lram_16(adv, s_addr, 0, mcode_lram_size);
143918781Sgibbs	adv_write_lram_16_multi(adv, s_addr, mcode_buf, mcode_lram_size);
144018781Sgibbs
144118781Sgibbs	chksum = adv_msum_lram_16(adv, s_addr, mcode_lram_size);
144218781Sgibbs	mcode_chksum = (u_int16_t)adv_msum_lram_16(adv, ADV_CODE_SEC_BEG,
144339217Sgibbs						   ((mcode_size - s_addr
144439217Sgibbs						     - ADV_CODE_SEC_BEG) >> 1));
144518781Sgibbs	adv_write_lram_16(adv, ADVV_MCODE_CHKSUM_W, mcode_chksum);
144618781Sgibbs	adv_write_lram_16(adv, ADVV_MCODE_SIZE_W, mcode_size);
144718781Sgibbs	return (chksum);
144818781Sgibbs}
144918781Sgibbs
145018781Sgibbsstatic void
145139217Sgibbsadv_reinit_lram(struct adv_softc *adv) {
145239217Sgibbs	adv_init_lram(adv);
145339217Sgibbs	adv_init_qlink_var(adv);
145439217Sgibbs}
145539217Sgibbs
145639217Sgibbsstatic void
145739217Sgibbsadv_init_lram(struct adv_softc *adv)
145818781Sgibbs{
145939217Sgibbs	u_int8_t  i;
146039217Sgibbs	u_int16_t s_addr;
146118781Sgibbs
146218781Sgibbs	adv_mset_lram_16(adv, ADV_QADR_BEG, 0,
146339217Sgibbs			 (((adv->max_openings + 2 + 1) * 64) >> 1));
146418781Sgibbs
146518781Sgibbs	i = ADV_MIN_ACTIVE_QNO;
146618781Sgibbs	s_addr = ADV_QADR_BEG + ADV_QBLK_SIZE;
146718781Sgibbs
146818781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD,	i + 1);
146918781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, adv->max_openings);
147018781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i);
147118781Sgibbs	i++;
147218781Sgibbs	s_addr += ADV_QBLK_SIZE;
147318781Sgibbs	for (; i < adv->max_openings; i++, s_addr += ADV_QBLK_SIZE) {
147418781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i + 1);
147518781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, i - 1);
147618781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i);
147718781Sgibbs	}
147818781Sgibbs
147918781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, ADV_QLINK_END);
148018781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, adv->max_openings - 1);
148118781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, adv->max_openings);
148218781Sgibbs	i++;
148318781Sgibbs	s_addr += ADV_QBLK_SIZE;
148418781Sgibbs
148518781Sgibbs	for (; i <= adv->max_openings + 3; i++, s_addr += ADV_QBLK_SIZE) {
148618781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i);
148718781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, i);
148818781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i);
148918781Sgibbs	}
149018781Sgibbs}
149118781Sgibbs
149218781Sgibbsstatic int
149339217Sgibbsadv_init_microcode_var(struct adv_softc *adv)
149418781Sgibbs{
149539217Sgibbs	int	 i;
149618781Sgibbs
149718781Sgibbs	for (i = 0; i <= ADV_MAX_TID; i++) {
149839217Sgibbs
149939217Sgibbs		/* Start out async all around */
150039217Sgibbs		adv_set_syncrate(adv, /*path*/NULL,
150139217Sgibbs				 i, 0, 0,
150239217Sgibbs				 ADV_TRANS_GOAL|ADV_TRANS_CUR);
150318781Sgibbs	}
150418781Sgibbs
150518781Sgibbs	adv_init_qlink_var(adv);
150618781Sgibbs
150718781Sgibbs	adv_write_lram_8(adv, ADVV_DISC_ENABLE_B, adv->disc_enable);
150818781Sgibbs	adv_write_lram_8(adv, ADVV_HOSTSCSI_ID_B, 0x01 << adv->scsi_id);
150918781Sgibbs
151039217Sgibbs	adv_write_lram_32(adv, ADVV_OVERRUN_PADDR_D, adv->overrun_physbase);
151118781Sgibbs
151239217Sgibbs	adv_write_lram_32(adv, ADVV_OVERRUN_BSIZE_D, ADV_OVERRUN_BSIZE);
151318781Sgibbs
151418781Sgibbs	ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR);
151518781Sgibbs	if (ADV_INW(adv, ADV_REG_PROG_COUNTER) != ADV_MCODE_START_ADDR) {
1516251164Sscottl		device_printf(adv->dev,
1517251164Sscottl		    "Unable to set program counter. Aborting.\n");
151818781Sgibbs		return (1);
151918781Sgibbs	}
152018781Sgibbs	return (0);
152118781Sgibbs}
152218781Sgibbs
152318781Sgibbsstatic void
152439217Sgibbsadv_init_qlink_var(struct adv_softc *adv)
152518781Sgibbs{
152618781Sgibbs	int	  i;
152718781Sgibbs	u_int16_t lram_addr;
152818781Sgibbs
152918781Sgibbs	adv_write_lram_8(adv, ADVV_NEXTRDY_B, 1);
153018781Sgibbs	adv_write_lram_8(adv, ADVV_DONENEXT_B, adv->max_openings);
153118781Sgibbs
153218781Sgibbs	adv_write_lram_16(adv, ADVV_FREE_Q_HEAD_W, 1);
153318781Sgibbs	adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, adv->max_openings);
153418781Sgibbs
153518781Sgibbs	adv_write_lram_8(adv, ADVV_BUSY_QHEAD_B,
153618781Sgibbs			 (u_int8_t)((int) adv->max_openings + 1));
153718781Sgibbs	adv_write_lram_8(adv, ADVV_DISC1_QHEAD_B,
153818781Sgibbs			 (u_int8_t)((int) adv->max_openings + 2));
153918781Sgibbs
154018781Sgibbs	adv_write_lram_8(adv, ADVV_TOTAL_READY_Q_B, adv->max_openings);
154118781Sgibbs
154218781Sgibbs	adv_write_lram_16(adv, ADVV_ASCDVC_ERR_CODE_W, 0);
154318781Sgibbs	adv_write_lram_16(adv, ADVV_HALTCODE_W, 0);
154418781Sgibbs	adv_write_lram_8(adv, ADVV_STOP_CODE_B, 0);
154518781Sgibbs	adv_write_lram_8(adv, ADVV_SCSIBUSY_B, 0);
154618781Sgibbs	adv_write_lram_8(adv, ADVV_WTM_FLAG_B, 0);
154739217Sgibbs	adv_write_lram_8(adv, ADVV_Q_DONE_IN_PROGRESS_B, 0);
154818781Sgibbs
154918781Sgibbs	lram_addr = ADV_QADR_BEG;
155018781Sgibbs	for (i = 0; i < 32; i++, lram_addr += 2)
155118781Sgibbs		adv_write_lram_16(adv, lram_addr, 0);
155218781Sgibbs}
155339217Sgibbs
155418781Sgibbsstatic void
155539217Sgibbsadv_disable_interrupt(struct adv_softc *adv)
155618781Sgibbs{
155718781Sgibbs	u_int16_t cfg;
155818781Sgibbs
155918781Sgibbs	cfg = ADV_INW(adv, ADV_CONFIG_LSW);
156018781Sgibbs	ADV_OUTW(adv, ADV_CONFIG_LSW, cfg & ~ADV_CFG_LSW_HOST_INT_ON);
156118781Sgibbs}
156218781Sgibbs
156318781Sgibbsstatic void
156439217Sgibbsadv_enable_interrupt(struct adv_softc *adv)
156518781Sgibbs{
156618781Sgibbs	u_int16_t cfg;
156718781Sgibbs
156818781Sgibbs	cfg = ADV_INW(adv, ADV_CONFIG_LSW);
156918781Sgibbs	ADV_OUTW(adv, ADV_CONFIG_LSW, cfg | ADV_CFG_LSW_HOST_INT_ON);
157018781Sgibbs}
157118781Sgibbs
157218781Sgibbsstatic void
157339217Sgibbsadv_toggle_irq_act(struct adv_softc *adv)
157418781Sgibbs{
157518781Sgibbs	ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_IRQ_ACT);
157618781Sgibbs	ADV_OUTW(adv, ADV_CHIP_STATUS, 0);
157718781Sgibbs}
157818781Sgibbs
157939217Sgibbsvoid
158039217Sgibbsadv_start_execution(struct adv_softc *adv)
158118781Sgibbs{
158218781Sgibbs	if (adv_read_lram_8(adv, ADV_STOP_CODE_B) != 0) {
158318781Sgibbs		adv_write_lram_8(adv, ADV_STOP_CODE_B, 0);
158418781Sgibbs	}
158518781Sgibbs}
158618781Sgibbs
158755945Sgibbsint
158839217Sgibbsadv_stop_chip(struct adv_softc *adv)
158918781Sgibbs{
159018781Sgibbs	u_int8_t cc_val;
159118781Sgibbs
159218781Sgibbs	cc_val = ADV_INB(adv, ADV_CHIP_CTRL)
159318781Sgibbs		 & (~(ADV_CC_SINGLE_STEP | ADV_CC_TEST | ADV_CC_DIAG));
159418781Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, cc_val | ADV_CC_HALT);
159518781Sgibbs	adv_set_chip_ih(adv, ADV_INS_HALT);
159618781Sgibbs	adv_set_chip_ih(adv, ADV_INS_RFLAG_WTM);
159718781Sgibbs	if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) == 0) {
159818781Sgibbs		return (0);
159918781Sgibbs	}
160018781Sgibbs	return (1);
160118781Sgibbs}
160218781Sgibbs
160339217Sgibbsstatic int
160439217Sgibbsadv_host_req_chip_halt(struct adv_softc *adv)
160539217Sgibbs{
160639217Sgibbs	int	 count;
160739217Sgibbs	u_int8_t saved_stop_code;
160839217Sgibbs
160939217Sgibbs	if (adv_is_chip_halted(adv))
161039217Sgibbs		return (1);
161139217Sgibbs
161239217Sgibbs	count = 0;
161339217Sgibbs	saved_stop_code = adv_read_lram_8(adv, ADVV_STOP_CODE_B);
161439217Sgibbs	adv_write_lram_8(adv, ADVV_STOP_CODE_B,
161539217Sgibbs			 ADV_STOP_HOST_REQ_RISC_HALT | ADV_STOP_REQ_RISC_STOP);
161639217Sgibbs	while (adv_is_chip_halted(adv) == 0
161739217Sgibbs	    && count++ < 2000)
161839217Sgibbs		;
161939217Sgibbs
162039217Sgibbs	adv_write_lram_8(adv, ADVV_STOP_CODE_B, saved_stop_code);
162139217Sgibbs	return (count < 2000);
162239217Sgibbs}
162339217Sgibbs
162418781Sgibbsstatic void
162539217Sgibbsadv_set_chip_ih(struct adv_softc *adv, u_int16_t ins_code)
162618781Sgibbs{
162718781Sgibbs	adv_set_bank(adv, 1);
162818781Sgibbs	ADV_OUTW(adv, ADV_REG_IH, ins_code);
162918781Sgibbs	adv_set_bank(adv, 0);
163018781Sgibbs}
163118781Sgibbs
1632153072Sru#if 0
163318781Sgibbsstatic u_int8_t
163439217Sgibbsadv_get_chip_scsi_ctrl(struct adv_softc *adv)
163518781Sgibbs{
163618781Sgibbs	u_int8_t scsi_ctrl;
163718781Sgibbs
163818781Sgibbs	adv_set_bank(adv, 1);
163918781Sgibbs	scsi_ctrl = ADV_INB(adv, ADV_REG_SC);
164018781Sgibbs	adv_set_bank(adv, 0);
164118781Sgibbs	return (scsi_ctrl);
164218781Sgibbs}
164318781Sgibbs#endif
164418781Sgibbs
164518781Sgibbs/*
164618781Sgibbs * XXX Looks like more padding issues in this routine as well.
164718781Sgibbs *     There has to be a way to turn this into an insw.
164818781Sgibbs */
164918781Sgibbsstatic void
165039217Sgibbsadv_get_q_info(struct adv_softc *adv, u_int16_t s_addr,
165139217Sgibbs	       u_int16_t *inbuf, int words)
165218781Sgibbs{
165318781Sgibbs	int	i;
165418781Sgibbs
165518781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
165618781Sgibbs	for (i = 0; i < words; i++, inbuf++) {
165718781Sgibbs		if (i == 5) {
165818781Sgibbs			continue;
165918781Sgibbs		}
166018781Sgibbs		*inbuf = ADV_INW(adv, ADV_LRAM_DATA);
166118781Sgibbs	}
166218781Sgibbs}
166318781Sgibbs
166418781Sgibbsstatic u_int
166539217Sgibbsadv_get_num_free_queues(struct adv_softc *adv, u_int8_t n_qs)
166618781Sgibbs{
166718781Sgibbs	u_int	  cur_used_qs;
166818781Sgibbs	u_int	  cur_free_qs;
166918781Sgibbs
167039217Sgibbs	cur_used_qs = adv->cur_active + ADV_MIN_FREE_Q;
167118781Sgibbs
167218781Sgibbs	if ((cur_used_qs + n_qs) <= adv->max_openings) {
167318781Sgibbs		cur_free_qs = adv->max_openings - cur_used_qs;
167418781Sgibbs		return (cur_free_qs);
167518781Sgibbs	}
167639217Sgibbs	adv->openings_needed = n_qs;
167718781Sgibbs	return (0);
167818781Sgibbs}
167918781Sgibbs
168018781Sgibbsstatic u_int8_t
168139217Sgibbsadv_alloc_free_queues(struct adv_softc *adv, u_int8_t free_q_head,
168239217Sgibbs		      u_int8_t n_free_q)
168318781Sgibbs{
168418781Sgibbs	int i;
168518781Sgibbs
168618781Sgibbs	for (i = 0; i < n_free_q; i++) {
168718781Sgibbs		free_q_head = adv_alloc_free_queue(adv, free_q_head);
168818781Sgibbs		if (free_q_head == ADV_QLINK_END)
168918781Sgibbs			break;
169018781Sgibbs	}
169118781Sgibbs	return (free_q_head);
169218781Sgibbs}
169318781Sgibbs
169418781Sgibbsstatic u_int8_t
169539217Sgibbsadv_alloc_free_queue(struct adv_softc *adv, u_int8_t free_q_head)
169618781Sgibbs{
169718781Sgibbs	u_int16_t	q_addr;
169818781Sgibbs	u_int8_t	next_qp;
169918781Sgibbs	u_int8_t	q_status;
170018781Sgibbs
170118781Sgibbs	next_qp = ADV_QLINK_END;
170218781Sgibbs	q_addr = ADV_QNO_TO_QADDR(free_q_head);
170318781Sgibbs	q_status = adv_read_lram_8(adv,	q_addr + ADV_SCSIQ_B_STATUS);
170418781Sgibbs
170518781Sgibbs	if ((q_status & QS_READY) == 0)
170618781Sgibbs		next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD);
170718781Sgibbs
170818781Sgibbs	return (next_qp);
170918781Sgibbs}
171018781Sgibbs
171118781Sgibbsstatic int
171239217Sgibbsadv_send_scsi_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq,
171339217Sgibbs		    u_int8_t n_q_required)
171418781Sgibbs{
171518781Sgibbs	u_int8_t	free_q_head;
171618781Sgibbs	u_int8_t	next_qp;
171718781Sgibbs	u_int8_t	tid_no;
171818781Sgibbs	u_int8_t	target_ix;
171918781Sgibbs	int		retval;
172018781Sgibbs
172118781Sgibbs	retval = 1;
172218781Sgibbs	target_ix = scsiq->q2.target_ix;
172318781Sgibbs	tid_no = ADV_TIX_TO_TID(target_ix);
172418781Sgibbs	free_q_head = adv_read_lram_16(adv, ADVV_FREE_Q_HEAD_W) & 0xFF;
172518781Sgibbs	if ((next_qp = adv_alloc_free_queues(adv, free_q_head, n_q_required))
172618781Sgibbs	    != ADV_QLINK_END) {
172718781Sgibbs		scsiq->q1.q_no = free_q_head;
172818781Sgibbs
172918781Sgibbs		/*
173018781Sgibbs		 * Now that we know our Q number, point our sense
173139217Sgibbs		 * buffer pointer to a bus dma mapped area where
173239217Sgibbs		 * we can dma the data to.
173318781Sgibbs		 */
173439217Sgibbs		scsiq->q1.sense_addr = adv->sense_physbase
173539217Sgibbs		    + ((free_q_head - 1) * sizeof(struct scsi_sense_data));
173618781Sgibbs		adv_put_ready_sg_list_queue(adv, scsiq, free_q_head);
173718781Sgibbs		adv_write_lram_16(adv, ADVV_FREE_Q_HEAD_W, next_qp);
173818781Sgibbs		adv->cur_active += n_q_required;
173918781Sgibbs		retval = 0;
174018781Sgibbs	}
174118781Sgibbs	return (retval);
174218781Sgibbs}
174318781Sgibbs
174418781Sgibbs
174518781Sgibbsstatic void
174639217Sgibbsadv_put_ready_sg_list_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq,
174739217Sgibbs			    u_int q_no)
174818781Sgibbs{
174918781Sgibbs	u_int8_t	sg_list_dwords;
175018781Sgibbs	u_int8_t	sg_index, i;
175118781Sgibbs	u_int8_t	sg_entry_cnt;
175218781Sgibbs	u_int8_t	next_qp;
175318781Sgibbs	u_int16_t	q_addr;
175418781Sgibbs	struct		adv_sg_head *sg_head;
175518781Sgibbs	struct		adv_sg_list_q scsi_sg_q;
175618781Sgibbs
175718781Sgibbs	sg_head = scsiq->sg_head;
175818781Sgibbs
175918781Sgibbs	if (sg_head) {
176018781Sgibbs		sg_entry_cnt = sg_head->entry_cnt - 1;
176118781Sgibbs#ifdef DIAGNOSTIC
176218781Sgibbs		if (sg_entry_cnt == 0)
176339217Sgibbs			panic("adv_put_ready_sg_list_queue: ScsiQ with "
176439217Sgibbs			      "a SG list but only one element");
176518781Sgibbs		if ((scsiq->q1.cntl & QC_SG_HEAD) == 0)
176639217Sgibbs			panic("adv_put_ready_sg_list_queue: ScsiQ with "
176739217Sgibbs			      "a SG list but QC_SG_HEAD not set");
176818781Sgibbs#endif
176918781Sgibbs		q_addr = ADV_QNO_TO_QADDR(q_no);
177018781Sgibbs		sg_index = 1;
177118781Sgibbs		scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
177218781Sgibbs		scsi_sg_q.sg_head_qp = q_no;
177318781Sgibbs		scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
177418781Sgibbs		for (i = 0; i < sg_head->queue_cnt; i++) {
177518781Sgibbs			u_int8_t segs_this_q;
177618781Sgibbs
177718781Sgibbs			if (sg_entry_cnt > ADV_SG_LIST_PER_Q)
177818781Sgibbs				segs_this_q = ADV_SG_LIST_PER_Q;
177918781Sgibbs			else {
178018781Sgibbs				/* This will be the last segment then */
178118781Sgibbs				segs_this_q = sg_entry_cnt;
178218781Sgibbs				scsi_sg_q.cntl |= QCSG_SG_XFER_END;
178318781Sgibbs			}
178418781Sgibbs			scsi_sg_q.seq_no = i + 1;
178539217Sgibbs			sg_list_dwords = segs_this_q << 1;
178618781Sgibbs			if (i == 0) {
178718781Sgibbs				scsi_sg_q.sg_list_cnt = segs_this_q;
178818781Sgibbs				scsi_sg_q.sg_cur_list_cnt = segs_this_q;
178918781Sgibbs			} else {
179018781Sgibbs				scsi_sg_q.sg_list_cnt = segs_this_q - 1;
179118781Sgibbs				scsi_sg_q.sg_cur_list_cnt = segs_this_q - 1;
179218781Sgibbs			}
179318781Sgibbs			next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD);
179418781Sgibbs			scsi_sg_q.q_no = next_qp;
179518781Sgibbs			q_addr = ADV_QNO_TO_QADDR(next_qp);
179618781Sgibbs
179739217Sgibbs			adv_write_lram_16_multi(adv,
179839217Sgibbs						q_addr + ADV_SCSIQ_SGHD_CPY_BEG,
179918781Sgibbs						(u_int16_t *)&scsi_sg_q,
180018781Sgibbs						sizeof(scsi_sg_q) >> 1);
180118781Sgibbs			adv_write_lram_32_multi(adv, q_addr + ADV_SGQ_LIST_BEG,
180218781Sgibbs						(u_int32_t *)&sg_head->sg_list[sg_index],
180318781Sgibbs						sg_list_dwords);
180418781Sgibbs			sg_entry_cnt -= segs_this_q;
180518781Sgibbs			sg_index += ADV_SG_LIST_PER_Q;
180618781Sgibbs		}
180718781Sgibbs	}
180818781Sgibbs	adv_put_ready_queue(adv, scsiq, q_no);
180918781Sgibbs}
181018781Sgibbs
181118781Sgibbsstatic void
181239217Sgibbsadv_put_ready_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq,
181339217Sgibbs		    u_int q_no)
181418781Sgibbs{
181539217Sgibbs	struct		adv_target_transinfo* tinfo;
181639217Sgibbs	u_int		q_addr;
181739217Sgibbs	u_int		tid_no;
181818781Sgibbs
181939217Sgibbs	tid_no = ADV_TIX_TO_TID(scsiq->q2.target_ix);
182039217Sgibbs	tinfo = &adv->tinfo[tid_no];
182146581Sken	if ((tinfo->current.period != tinfo->goal.period)
182246581Sken	 || (tinfo->current.offset != tinfo->goal.offset)) {
182318781Sgibbs
182439217Sgibbs		adv_msgout_sdtr(adv, tinfo->goal.period, tinfo->goal.offset);
182518781Sgibbs		scsiq->q1.cntl |= QC_MSG_OUT;
182618781Sgibbs	}
182718781Sgibbs	q_addr = ADV_QNO_TO_QADDR(q_no);
182818781Sgibbs
182918781Sgibbs	scsiq->q1.status = QS_FREE;
183018781Sgibbs
183118781Sgibbs	adv_write_lram_16_multi(adv, q_addr + ADV_SCSIQ_CDB_BEG,
183218781Sgibbs				(u_int16_t *)scsiq->cdbptr,
183318781Sgibbs				scsiq->q2.cdb_len >> 1);
183418781Sgibbs
183518781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
183618781Sgibbs	adv_adj_scsiq_endian(scsiq);
183718781Sgibbs#endif
183818781Sgibbs
183918781Sgibbs	adv_put_scsiq(adv, q_addr + ADV_SCSIQ_CPY_BEG,
184018781Sgibbs		      (u_int16_t *) &scsiq->q1.cntl,
184118781Sgibbs		      ((sizeof(scsiq->q1) + sizeof(scsiq->q2)) / 2) - 1);
184218781Sgibbs
1843153072Sru#ifdef CC_WRITE_IO_COUNT
184418781Sgibbs	adv_write_lram_16(adv, q_addr + ADV_SCSIQ_W_REQ_COUNT,
184518781Sgibbs			  adv->req_count);
184618781Sgibbs#endif
184718781Sgibbs
1848153072Sru#ifdef CC_CLEAR_DMA_REMAIN
184918781Sgibbs
185018781Sgibbs	adv_write_lram_32(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_ADDR, 0);
185118781Sgibbs	adv_write_lram_32(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_CNT, 0);
185218781Sgibbs#endif
185318781Sgibbs
185418781Sgibbs	adv_write_lram_16(adv, q_addr + ADV_SCSIQ_B_STATUS,
185518781Sgibbs			  (scsiq->q1.q_no << 8) | QS_READY);
185618781Sgibbs}
185718781Sgibbs
185818781Sgibbsstatic void
185939217Sgibbsadv_put_scsiq(struct adv_softc *adv, u_int16_t s_addr,
186039217Sgibbs	      u_int16_t *buffer, int words)
186118781Sgibbs{
186218781Sgibbs	int	i;
186318781Sgibbs
186418781Sgibbs	/*
186518781Sgibbs	 * XXX This routine makes *gross* assumptions
186618781Sgibbs	 * about padding in the data structures.
186718781Sgibbs	 * Either the data structures should have explicit
186818781Sgibbs	 * padding members added, or they should have padding
186918781Sgibbs	 * turned off via compiler attributes depending on
187018781Sgibbs	 * which yields better overall performance.  My hunch
187118781Sgibbs	 * would be that turning off padding would be the
187218781Sgibbs	 * faster approach as an outsw is much faster than
187318781Sgibbs	 * this crude loop and accessing un-aligned data
187418781Sgibbs	 * members isn't *that* expensive.  The other choice
187518781Sgibbs	 * would be to modify the ASC script so that the
187618781Sgibbs	 * the adv_scsiq_1 structure can be re-arranged so
187718781Sgibbs	 * padding isn't required.
187818781Sgibbs	 */
187918781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
188018781Sgibbs	for (i = 0; i < words; i++, buffer++) {
188118781Sgibbs		if (i == 2 || i == 10) {
188218781Sgibbs			continue;
188318781Sgibbs		}
188418781Sgibbs		ADV_OUTW(adv, ADV_LRAM_DATA, *buffer);
188518781Sgibbs	}
188618781Sgibbs}
188718781Sgibbs
1888111342Sobrien#if BYTE_ORDER == BIG_ENDIAN
1889111342Sobrienvoid
1890111342Sobrienadv_adj_endian_qdone_info(struct adv_q_done_info *scsiq)
1891111342Sobrien{
1892111342Sobrien
1893111342Sobrien	panic("adv(4) not supported on big-endian machines.\n");
1894111342Sobrien}
1895111342Sobrien
1896111342Sobrienvoid
1897111342Sobrienadv_adj_scsiq_endian(struct adv_scsi_q *scsiq)
1898111342Sobrien{
1899111342Sobrien
1900111342Sobrien	panic("adv(4) not supported on big-endian machines.\n");
1901111342Sobrien}
1902111342Sobrien#endif
1903111342Sobrien
190439217Sgibbsstatic void
190539217Sgibbsadv_handle_extmsg_in(struct adv_softc *adv, u_int16_t halt_q_addr,
190639217Sgibbs		     u_int8_t q_cntl, target_bit_vector target_mask,
190739217Sgibbs		     int tid_no)
190818781Sgibbs{
190939217Sgibbs	struct	ext_msg ext_msg;
191018781Sgibbs
191139217Sgibbs	adv_read_lram_16_multi(adv, ADVV_MSGIN_BEG, (u_int16_t *) &ext_msg,
191239217Sgibbs			       sizeof(ext_msg) >> 1);
191339217Sgibbs	if ((ext_msg.msg_type == MSG_EXTENDED)
191439217Sgibbs	 && (ext_msg.msg_req == MSG_EXT_SDTR)
191539217Sgibbs	 && (ext_msg.msg_len == MSG_EXT_SDTR_LEN)) {
191655945Sgibbs		union	  ccb *ccb;
191755945Sgibbs		struct	  adv_target_transinfo* tinfo;
191855945Sgibbs		u_int32_t cinfo_index;
191939217Sgibbs		u_int	 period;
192039217Sgibbs		u_int	 offset;
192139217Sgibbs		int	 sdtr_accept;
192239217Sgibbs		u_int8_t orig_offset;
192339217Sgibbs
192455945Sgibbs		cinfo_index =
192555945Sgibbs		    adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX);
192655945Sgibbs		ccb = adv->ccb_infos[cinfo_index].ccb;
192739217Sgibbs		tinfo = &adv->tinfo[tid_no];
192839217Sgibbs		sdtr_accept = TRUE;
192939217Sgibbs
193039217Sgibbs		orig_offset = ext_msg.req_ack_offset;
193139217Sgibbs		if (ext_msg.xfer_period < tinfo->goal.period) {
193239217Sgibbs                	sdtr_accept = FALSE;
193339217Sgibbs			ext_msg.xfer_period = tinfo->goal.period;
193439217Sgibbs		}
193539217Sgibbs
193639217Sgibbs		/* Perform range checking */
193739217Sgibbs		period = ext_msg.xfer_period;
193839217Sgibbs		offset = ext_msg.req_ack_offset;
193939217Sgibbs		adv_period_offset_to_sdtr(adv, &period,  &offset, tid_no);
194039217Sgibbs		ext_msg.xfer_period = period;
194139217Sgibbs		ext_msg.req_ack_offset = offset;
194239217Sgibbs
194339217Sgibbs		/* Record our current sync settings */
194439217Sgibbs		adv_set_syncrate(adv, ccb->ccb_h.path,
194539217Sgibbs				 tid_no, ext_msg.xfer_period,
194639217Sgibbs				 ext_msg.req_ack_offset,
194739217Sgibbs				 ADV_TRANS_GOAL|ADV_TRANS_ACTIVE);
194839217Sgibbs
194939217Sgibbs		/* Offset too high or large period forced async */
195039217Sgibbs		if (orig_offset != ext_msg.req_ack_offset)
195139217Sgibbs			sdtr_accept = FALSE;
195239217Sgibbs
195339217Sgibbs		if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
195439217Sgibbs			/* Valid response to our requested negotiation */
195539217Sgibbs			q_cntl &= ~QC_MSG_OUT;
195639217Sgibbs		} else {
195739217Sgibbs			/* Must Respond */
195839217Sgibbs			q_cntl |= QC_MSG_OUT;
195939217Sgibbs			adv_msgout_sdtr(adv, ext_msg.xfer_period,
196039217Sgibbs					ext_msg.req_ack_offset);
196139217Sgibbs		}
196239217Sgibbs
196339217Sgibbs	} else if (ext_msg.msg_type == MSG_EXTENDED
196439217Sgibbs		&& ext_msg.msg_req == MSG_EXT_WDTR
196539217Sgibbs		&& ext_msg.msg_len == MSG_EXT_WDTR_LEN) {
196639217Sgibbs
196739217Sgibbs		ext_msg.wdtr_width = 0;
196839217Sgibbs		adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG,
196939217Sgibbs					(u_int16_t *)&ext_msg,
197039217Sgibbs					sizeof(ext_msg) >> 1);
197139217Sgibbs		q_cntl |= QC_MSG_OUT;
197239217Sgibbs        } else {
197339217Sgibbs
197439217Sgibbs		ext_msg.msg_type = MSG_MESSAGE_REJECT;
197539217Sgibbs		adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG,
197639217Sgibbs					(u_int16_t *)&ext_msg,
197739217Sgibbs					sizeof(ext_msg) >> 1);
197839217Sgibbs		q_cntl |= QC_MSG_OUT;
197939217Sgibbs        }
198039217Sgibbs	adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl);
198139217Sgibbs}
198239217Sgibbs
198339217Sgibbsstatic void
198439217Sgibbsadv_msgout_sdtr(struct adv_softc *adv, u_int8_t sdtr_period,
198539217Sgibbs		u_int8_t sdtr_offset)
198639217Sgibbs{
198739217Sgibbs	struct	 ext_msg sdtr_buf;
198839217Sgibbs
198918781Sgibbs	sdtr_buf.msg_type = MSG_EXTENDED;
199018781Sgibbs	sdtr_buf.msg_len = MSG_EXT_SDTR_LEN;
199118781Sgibbs	sdtr_buf.msg_req = MSG_EXT_SDTR;
199218781Sgibbs	sdtr_buf.xfer_period = sdtr_period;
199318781Sgibbs	sdtr_offset &= ADV_SYN_MAX_OFFSET;
199418781Sgibbs	sdtr_buf.req_ack_offset = sdtr_offset;
199518781Sgibbs	adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG,
199618781Sgibbs				(u_int16_t *) &sdtr_buf,
199718781Sgibbs				sizeof(sdtr_buf) / 2);
199818781Sgibbs}
199918781Sgibbs
200039217Sgibbsint
200139217Sgibbsadv_abort_ccb(struct adv_softc *adv, int target, int lun, union ccb *ccb,
200239217Sgibbs	      u_int32_t status, int queued_only)
200318781Sgibbs{
200439217Sgibbs	u_int16_t q_addr;
200539217Sgibbs	u_int8_t  q_no;
200639217Sgibbs	struct adv_q_done_info scsiq_buf;
200739217Sgibbs	struct adv_q_done_info *scsiq;
200839217Sgibbs	u_int8_t  target_ix;
200939217Sgibbs	int	  count;
201018781Sgibbs
2011251164Sscottl	if (!dumping)
2012251164Sscottl		mtx_assert(&adv->lock, MA_OWNED);
201339217Sgibbs	scsiq = &scsiq_buf;
201439217Sgibbs	target_ix = ADV_TIDLUN_TO_IX(target, lun);
201539217Sgibbs	count = 0;
201639217Sgibbs	for (q_no = ADV_MIN_ACTIVE_QNO; q_no <= adv->max_openings; q_no++) {
201755945Sgibbs		struct adv_ccb_info *ccb_info;
201839217Sgibbs		q_addr = ADV_QNO_TO_QADDR(q_no);
201939217Sgibbs
202039217Sgibbs		adv_copy_lram_doneq(adv, q_addr, scsiq, adv->max_dma_count);
202155945Sgibbs		ccb_info = &adv->ccb_infos[scsiq->d2.ccb_index];
202239217Sgibbs		if (((scsiq->q_status & QS_READY) != 0)
202339217Sgibbs		 && ((scsiq->q_status & QS_ABORTED) == 0)
202439217Sgibbs		 && ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)
202539217Sgibbs		 && (scsiq->d2.target_ix == target_ix)
202639217Sgibbs		 && (queued_only == 0
202739217Sgibbs		  || !(scsiq->q_status & (QS_DISC1|QS_DISC2|QS_BUSY|QS_DONE)))
202855945Sgibbs		 && (ccb == NULL || (ccb == ccb_info->ccb))) {
202939217Sgibbs			union ccb *aborted_ccb;
203039217Sgibbs			struct adv_ccb_info *cinfo;
203139217Sgibbs
203239217Sgibbs			scsiq->q_status |= QS_ABORTED;
203339217Sgibbs			adv_write_lram_8(adv, q_addr + ADV_SCSIQ_B_STATUS,
203439217Sgibbs					 scsiq->q_status);
203555945Sgibbs			aborted_ccb = ccb_info->ccb;
203639217Sgibbs			/* Don't clobber earlier error codes */
203739217Sgibbs			if ((aborted_ccb->ccb_h.status & CAM_STATUS_MASK)
203839217Sgibbs			  == CAM_REQ_INPROG)
203939217Sgibbs				aborted_ccb->ccb_h.status |= status;
204039217Sgibbs			cinfo = (struct adv_ccb_info *)
204139217Sgibbs			    aborted_ccb->ccb_h.ccb_cinfo_ptr;
204239217Sgibbs			cinfo->state |= ACCB_ABORT_QUEUED;
204339217Sgibbs			count++;
204418781Sgibbs		}
204518781Sgibbs	}
204639217Sgibbs	return (count);
204718781Sgibbs}
204818781Sgibbs
204939217Sgibbsint
205055945Sgibbsadv_reset_bus(struct adv_softc *adv, int initiate_bus_reset)
205139217Sgibbs{
205239217Sgibbs	int count;
205339217Sgibbs	int i;
205439217Sgibbs	union ccb *ccb;
205539217Sgibbs
2056251164Sscottl	if (!dumping)
2057251164Sscottl		mtx_assert(&adv->lock, MA_OWNED);
205855945Sgibbs	i = 200;
205955945Sgibbs	while ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_SCSI_RESET_ACTIVE) != 0
206055945Sgibbs	    && i--)
206155945Sgibbs		DELAY(1000);
206255945Sgibbs	adv_reset_chip(adv, initiate_bus_reset);
206339217Sgibbs	adv_reinit_lram(adv);
206455945Sgibbs	for (i = 0; i <= ADV_MAX_TID; i++)
206555945Sgibbs		adv_set_syncrate(adv, NULL, i, /*period*/0,
206655945Sgibbs				 /*offset*/0, ADV_TRANS_CUR);
206739217Sgibbs	ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR);
206839217Sgibbs
206939217Sgibbs	/* Tell the XPT layer that a bus reset occured */
207039217Sgibbs	if (adv->path != NULL)
207139217Sgibbs		xpt_async(AC_BUS_RESET, adv->path, NULL);
207239217Sgibbs
207339217Sgibbs	count = 0;
207439217Sgibbs	while ((ccb = (union ccb *)LIST_FIRST(&adv->pending_ccbs)) != NULL) {
207539217Sgibbs		if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG)
207639217Sgibbs			ccb->ccb_h.status |= CAM_SCSI_BUS_RESET;
207739217Sgibbs		adv_done(adv, ccb, QD_ABORTED_BY_HOST, 0, 0, 0);
207839217Sgibbs		count++;
207939217Sgibbs	}
208039217Sgibbs
208139217Sgibbs	adv_start_chip(adv);
208239217Sgibbs	return (count);
208339217Sgibbs}
208439217Sgibbs
208518781Sgibbsstatic void
208639217Sgibbsadv_set_sdtr_reg_at_id(struct adv_softc *adv, int tid, u_int8_t sdtr_data)
208718781Sgibbs{
208839217Sgibbs	int orig_id;
208939217Sgibbs
209039217Sgibbs    	adv_set_bank(adv, 1);
209139217Sgibbs    	orig_id = ffs(ADV_INB(adv, ADV_HOST_SCSIID)) - 1;
209239217Sgibbs    	ADV_OUTB(adv, ADV_HOST_SCSIID, tid);
209339217Sgibbs	if (ADV_INB(adv, ADV_HOST_SCSIID) == (0x01 << tid)) {
209439217Sgibbs		adv_set_bank(adv, 0);
209539217Sgibbs		ADV_OUTB(adv, ADV_SYN_OFFSET, sdtr_data);
209639217Sgibbs	}
209739217Sgibbs    	adv_set_bank(adv, 1);
209839217Sgibbs    	ADV_OUTB(adv, ADV_HOST_SCSIID, orig_id);
209939217Sgibbs	adv_set_bank(adv, 0);
210018781Sgibbs}
2101