advlib.c revision 153072
1139749Simp/*-
218781Sgibbs * Low level routines for the Advanced Systems Inc. SCSI controllers chips
318781Sgibbs *
455945Sgibbs * Copyright (c) 1996-1997, 1999-2000 Justin Gibbs.
518781Sgibbs * All rights reserved.
618781Sgibbs *
718781Sgibbs * Redistribution and use in source and binary forms, with or without
818781Sgibbs * modification, are permitted provided that the following conditions
918781Sgibbs * are met:
1018781Sgibbs * 1. Redistributions of source code must retain the above copyright
1139217Sgibbs *    notice, this list of conditions, and the following disclaimer,
1239217Sgibbs *    without modification, immediately at the beginning of the file.
1318781Sgibbs * 2. Redistributions in binary form must reproduce the above copyright
1418781Sgibbs *    notice, this list of conditions and the following disclaimer in the
1518781Sgibbs *    documentation and/or other materials provided with the distribution.
1618781Sgibbs * 3. The name of the author may not be used to endorse or promote products
1718781Sgibbs *    derived from this software without specific prior written permission.
1818781Sgibbs *
1918781Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2018781Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2118781Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2218781Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2318781Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2418781Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2518781Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2618781Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2718781Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2818781Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2918781Sgibbs * SUCH DAMAGE.
3018781Sgibbs */
31139749Simp/*-
3218781Sgibbs * Ported from:
3318781Sgibbs * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
3418781Sgibbs *
3518781Sgibbs * Copyright (c) 1995-1996 Advanced System Products, Inc.
3618781Sgibbs * All Rights Reserved.
3718781Sgibbs *
3818781Sgibbs * Redistribution and use in source and binary forms, with or without
3918781Sgibbs * modification, are permitted provided that redistributions of source
4018781Sgibbs * code retain the above copyright notice and this comment without
4118781Sgibbs * modification.
4218781Sgibbs */
4318781Sgibbs
44119418Sobrien#include <sys/cdefs.h>
45119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/advansys/advlib.c 153072 2005-12-04 02:12:43Z ru $");
46119418Sobrien
4718781Sgibbs#include <sys/param.h>
4845846Sgibbs#include <sys/kernel.h>
4918781Sgibbs#include <sys/systm.h>
5018781Sgibbs
5139217Sgibbs#include <machine/bus.h>
5259082Snyan#include <machine/resource.h>
5359082Snyan#include <sys/bus.h>
5459082Snyan#include <sys/rman.h>
5518781Sgibbs
5639217Sgibbs#include <cam/cam.h>
5739217Sgibbs#include <cam/cam_ccb.h>
5839217Sgibbs#include <cam/cam_sim.h>
5939217Sgibbs#include <cam/cam_xpt_sim.h>
6018781Sgibbs
6139217Sgibbs#include <cam/scsi/scsi_all.h>
6239217Sgibbs#include <cam/scsi/scsi_message.h>
6339217Sgibbs#include <cam/scsi/scsi_da.h>
6439217Sgibbs#include <cam/scsi/scsi_cd.h>
6539217Sgibbs
6618781Sgibbs#include <vm/vm.h>
6718781Sgibbs#include <vm/vm_param.h>
6818781Sgibbs#include <vm/pmap.h>
6918781Sgibbs
7039217Sgibbs#include <dev/advansys/advansys.h>
7118781Sgibbs#include <dev/advansys/advmcode.h>
7218781Sgibbs
7339217Sgibbsstruct adv_quirk_entry {
7439217Sgibbs	struct scsi_inquiry_pattern inq_pat;
7539217Sgibbs	u_int8_t quirks;
7639217Sgibbs#define ADV_QUIRK_FIX_ASYN_XFER_ALWAYS	0x01
7739217Sgibbs#define ADV_QUIRK_FIX_ASYN_XFER		0x02
7839217Sgibbs};
7939217Sgibbs
8039217Sgibbsstatic struct adv_quirk_entry adv_quirk_table[] =
8139217Sgibbs{
8239217Sgibbs	{
8339217Sgibbs		{ T_CDROM, SIP_MEDIA_REMOVABLE, "HP", "*", "*" },
8439217Sgibbs		ADV_QUIRK_FIX_ASYN_XFER_ALWAYS|ADV_QUIRK_FIX_ASYN_XFER
8539217Sgibbs	},
8639217Sgibbs	{
8739217Sgibbs		{ T_CDROM, SIP_MEDIA_REMOVABLE, "NEC", "CD-ROM DRIVE", "*" },
8839217Sgibbs		0
8939217Sgibbs	},
9039217Sgibbs	{
9139217Sgibbs		{
9239217Sgibbs		  T_SEQUENTIAL, SIP_MEDIA_REMOVABLE,
9339217Sgibbs		  "TANDBERG", " TDC 36", "*"
9439217Sgibbs		},
9539217Sgibbs		0
9639217Sgibbs	},
9739217Sgibbs	{
9839217Sgibbs		{ T_SEQUENTIAL, SIP_MEDIA_REMOVABLE, "WANGTEK", "*", "*" },
9939217Sgibbs		0
10039217Sgibbs	},
10139217Sgibbs	{
10239217Sgibbs		{
10339217Sgibbs		  T_PROCESSOR, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
10439217Sgibbs		  "*", "*", "*"
10539217Sgibbs		},
10639217Sgibbs		0
10739217Sgibbs	},
10839217Sgibbs	{
10939217Sgibbs		{
11039217Sgibbs		  T_SCANNER, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
11139217Sgibbs		  "*", "*", "*"
11239217Sgibbs		},
11339217Sgibbs		0
11439217Sgibbs	},
11539217Sgibbs	{
11639217Sgibbs		/* Default quirk entry */
11739217Sgibbs		{
11839217Sgibbs		  T_ANY, SIP_MEDIA_REMOVABLE|SIP_MEDIA_FIXED,
11939217Sgibbs		  /*vendor*/"*", /*product*/"*", /*revision*/"*"
12039217Sgibbs                },
12139217Sgibbs                ADV_QUIRK_FIX_ASYN_XFER,
12239217Sgibbs	}
12339217Sgibbs};
12439217Sgibbs
12518781Sgibbs/*
12618781Sgibbs * Allowable periods in ns
12718781Sgibbs */
12845575Seivindstatic u_int8_t adv_sdtr_period_tbl[] =
12918781Sgibbs{
13018781Sgibbs	25,
13118781Sgibbs	30,
13218781Sgibbs	35,
13318781Sgibbs	40,
13418781Sgibbs	50,
13518781Sgibbs	60,
13618781Sgibbs	70,
13718781Sgibbs	85
13818781Sgibbs};
13918781Sgibbs
14045575Seivindstatic u_int8_t adv_sdtr_period_tbl_ultra[] =
14139217Sgibbs{
14239217Sgibbs	12,
14339217Sgibbs	19,
14439217Sgibbs	25,
14539217Sgibbs	32,
14639217Sgibbs	38,
14739217Sgibbs	44,
14839217Sgibbs	50,
14939217Sgibbs	57,
15039217Sgibbs	63,
15139217Sgibbs	69,
15239217Sgibbs	75,
15339217Sgibbs	82,
15439217Sgibbs	88,
15539217Sgibbs	94,
15639217Sgibbs	100,
15739217Sgibbs	107
15818781Sgibbs};
15918781Sgibbs
16039217Sgibbsstruct ext_msg {
16139217Sgibbs	u_int8_t msg_type;
16239217Sgibbs	u_int8_t msg_len;
16339217Sgibbs	u_int8_t msg_req;
16439217Sgibbs	union {
16539217Sgibbs		struct {
16639217Sgibbs			u_int8_t sdtr_xfer_period;
16739217Sgibbs			u_int8_t sdtr_req_ack_offset;
16839217Sgibbs		} sdtr;
16939217Sgibbs		struct {
17039217Sgibbs       			u_int8_t wdtr_width;
17139217Sgibbs		} wdtr;
17239217Sgibbs		struct {
17339217Sgibbs			u_int8_t mdp[4];
17439217Sgibbs		} mdp;
17539217Sgibbs	} u_ext_msg;
17639217Sgibbs	u_int8_t res;
17739217Sgibbs};
17839217Sgibbs
17939217Sgibbs#define	xfer_period	u_ext_msg.sdtr.sdtr_xfer_period
18039217Sgibbs#define	req_ack_offset	u_ext_msg.sdtr.sdtr_req_ack_offset
18139217Sgibbs#define	wdtr_width	u_ext_msg.wdtr.wdtr_width
18239217Sgibbs#define	mdp_b3		u_ext_msg.mdp_b3
18339217Sgibbs#define	mdp_b2		u_ext_msg.mdp_b2
18439217Sgibbs#define	mdp_b1		u_ext_msg.mdp_b1
18539217Sgibbs#define	mdp_b0		u_ext_msg.mdp_b0
18639217Sgibbs
18718781Sgibbs/*
18818781Sgibbs * Some of the early PCI adapters have problems with
18939217Sgibbs * async transfers.  Instead use an offset of 1.
19018781Sgibbs */
19139217Sgibbs#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
19218781Sgibbs
19318781Sgibbs/* LRAM routines */
19439217Sgibbsstatic void	 adv_read_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr,
19539217Sgibbs					u_int16_t *buffer, int count);
19639217Sgibbsstatic void	 adv_write_lram_16_multi(struct adv_softc *adv,
19739217Sgibbs					 u_int16_t s_addr, u_int16_t *buffer,
19839217Sgibbs					 int count);
19939217Sgibbsstatic void	 adv_mset_lram_16(struct adv_softc *adv, u_int16_t s_addr,
20039217Sgibbs				  u_int16_t set_value, int count);
20139217Sgibbsstatic u_int32_t adv_msum_lram_16(struct adv_softc *adv, u_int16_t s_addr,
20239217Sgibbs				  int count);
20318781Sgibbs
20439217Sgibbsstatic int	 adv_write_and_verify_lram_16(struct adv_softc *adv,
20539217Sgibbs					      u_int16_t addr, u_int16_t value);
20639217Sgibbsstatic u_int32_t adv_read_lram_32(struct adv_softc *adv, u_int16_t addr);
20718781Sgibbs
20818781Sgibbs
20939217Sgibbsstatic void	 adv_write_lram_32(struct adv_softc *adv, u_int16_t addr,
21039217Sgibbs				   u_int32_t value);
21139217Sgibbsstatic void	 adv_write_lram_32_multi(struct adv_softc *adv,
21239217Sgibbs					 u_int16_t s_addr, u_int32_t *buffer,
21339217Sgibbs					 int count);
21418781Sgibbs
21518781Sgibbs/* EEPROM routines */
21639217Sgibbsstatic u_int16_t adv_read_eeprom_16(struct adv_softc *adv, u_int8_t addr);
21739217Sgibbsstatic u_int16_t adv_write_eeprom_16(struct adv_softc *adv, u_int8_t addr,
21839217Sgibbs				     u_int16_t value);
21939217Sgibbsstatic int	 adv_write_eeprom_cmd_reg(struct adv_softc *adv,
22039217Sgibbs					  u_int8_t cmd_reg);
22139217Sgibbsstatic int	 adv_set_eeprom_config_once(struct adv_softc *adv,
22239217Sgibbs					    struct adv_eeprom_config *eeconfig);
22318781Sgibbs
22418781Sgibbs/* Initialization */
22539217Sgibbsstatic u_int32_t adv_load_microcode(struct adv_softc *adv, u_int16_t s_addr,
22639217Sgibbs				    u_int16_t *mcode_buf, u_int16_t mcode_size);
22718781Sgibbs
22839217Sgibbsstatic void	 adv_reinit_lram(struct adv_softc *adv);
22939217Sgibbsstatic void	 adv_init_lram(struct adv_softc *adv);
23039217Sgibbsstatic int	 adv_init_microcode_var(struct adv_softc *adv);
23139217Sgibbsstatic void	 adv_init_qlink_var(struct adv_softc *adv);
23239217Sgibbs
23318781Sgibbs/* Interrupts */
23439217Sgibbsstatic void	 adv_disable_interrupt(struct adv_softc *adv);
23539217Sgibbsstatic void	 adv_enable_interrupt(struct adv_softc *adv);
23639217Sgibbsstatic void	 adv_toggle_irq_act(struct adv_softc *adv);
23718781Sgibbs
23818781Sgibbs/* Chip Control */
23939217Sgibbsstatic int	 adv_host_req_chip_halt(struct adv_softc *adv);
24039217Sgibbsstatic void	 adv_set_chip_ih(struct adv_softc *adv, u_int16_t ins_code);
241153072Sru#if 0
24239217Sgibbsstatic u_int8_t  adv_get_chip_scsi_ctrl(struct adv_softc *adv);
24318781Sgibbs#endif
24418781Sgibbs
24518781Sgibbs/* Queue handling and execution */
24640027Sgibbsstatic __inline int
24740027Sgibbs		 adv_sgcount_to_qcount(int sgcount);
24840027Sgibbs
24940027Sgibbsstatic __inline int
25040027Sgibbsadv_sgcount_to_qcount(int sgcount)
25140027Sgibbs{
25240027Sgibbs	int	n_sg_list_qs;
25340027Sgibbs
25440027Sgibbs	n_sg_list_qs = ((sgcount - 1) / ADV_SG_LIST_PER_Q);
25540027Sgibbs	if (((sgcount - 1) % ADV_SG_LIST_PER_Q) != 0)
25640027Sgibbs		n_sg_list_qs++;
25740027Sgibbs	return (n_sg_list_qs + 1);
25840027Sgibbs}
25940027Sgibbs
260111409Sobrien#if BYTE_ORDER == BIG_ENDIAN
261111342Sobrienstatic void	 adv_adj_endian_qdone_info(struct adv_q_done_info *);
262111342Sobrienstatic void	 adv_adj_scsiq_endian(struct adv_scsi_q *);
263111409Sobrien#endif
26439217Sgibbsstatic void	 adv_get_q_info(struct adv_softc *adv, u_int16_t s_addr,
26539217Sgibbs				u_int16_t *inbuf, int words);
26639217Sgibbsstatic u_int	 adv_get_num_free_queues(struct adv_softc *adv, u_int8_t n_qs);
26739217Sgibbsstatic u_int8_t  adv_alloc_free_queues(struct adv_softc *adv,
26839217Sgibbs				       u_int8_t free_q_head, u_int8_t n_free_q);
26939217Sgibbsstatic u_int8_t  adv_alloc_free_queue(struct adv_softc *adv,
27039217Sgibbs				      u_int8_t free_q_head);
27139217Sgibbsstatic int	 adv_send_scsi_queue(struct adv_softc *adv,
27239217Sgibbs				     struct adv_scsi_q *scsiq,
27339217Sgibbs				     u_int8_t n_q_required);
27439217Sgibbsstatic void	 adv_put_ready_sg_list_queue(struct adv_softc *adv,
27539217Sgibbs					     struct adv_scsi_q *scsiq,
27639217Sgibbs					     u_int q_no);
27739217Sgibbsstatic void	 adv_put_ready_queue(struct adv_softc *adv,
27839217Sgibbs				     struct adv_scsi_q *scsiq, u_int q_no);
27939217Sgibbsstatic void	 adv_put_scsiq(struct adv_softc *adv, u_int16_t s_addr,
28039217Sgibbs			       u_int16_t *buffer, int words);
28118781Sgibbs
28239217Sgibbs/* Messages */
28339217Sgibbsstatic void	 adv_handle_extmsg_in(struct adv_softc *adv,
28439217Sgibbs				      u_int16_t halt_q_addr, u_int8_t q_cntl,
28539217Sgibbs				      target_bit_vector target_id,
28639217Sgibbs				      int tid);
28739217Sgibbsstatic void	 adv_msgout_sdtr(struct adv_softc *adv, u_int8_t sdtr_period,
28839217Sgibbs				 u_int8_t sdtr_offset);
28939217Sgibbsstatic void	 adv_set_sdtr_reg_at_id(struct adv_softc *adv, int id,
29039217Sgibbs					u_int8_t sdtr_data);
29118781Sgibbs
29218781Sgibbs
29319426Sgibbs/* Exported functions first */
29418781Sgibbs
29539217Sgibbsvoid
29639217Sgibbsadvasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg)
29739217Sgibbs{
29818781Sgibbs	struct adv_softc *adv;
29939217Sgibbs
30039217Sgibbs	adv = (struct adv_softc *)callback_arg;
30139217Sgibbs	switch (code) {
30239217Sgibbs	case AC_FOUND_DEVICE:
30339217Sgibbs	{
30439217Sgibbs		struct ccb_getdev *cgd;
30539217Sgibbs		target_bit_vector target_mask;
30639217Sgibbs		int num_entries;
30739217Sgibbs        	caddr_t match;
30839217Sgibbs		struct adv_quirk_entry *entry;
30939217Sgibbs		struct adv_target_transinfo* tinfo;
31039217Sgibbs
31139217Sgibbs		cgd = (struct ccb_getdev *)arg;
31239217Sgibbs
31339217Sgibbs		target_mask = ADV_TID_TO_TARGET_MASK(cgd->ccb_h.target_id);
31439217Sgibbs
31539217Sgibbs		num_entries = sizeof(adv_quirk_table)/sizeof(*adv_quirk_table);
31639217Sgibbs		match = cam_quirkmatch((caddr_t)&cgd->inq_data,
31739217Sgibbs				       (caddr_t)adv_quirk_table,
31839217Sgibbs				       num_entries, sizeof(*adv_quirk_table),
31939217Sgibbs				       scsi_inquiry_match);
32039217Sgibbs
32139217Sgibbs		if (match == NULL)
32239217Sgibbs			panic("advasync: device didn't match wildcard entry!!");
32339217Sgibbs
32439217Sgibbs		entry = (struct adv_quirk_entry *)match;
32539217Sgibbs
32639217Sgibbs		if (adv->bug_fix_control & ADV_BUG_FIX_ASYN_USE_SYN) {
32739217Sgibbs			if ((entry->quirks & ADV_QUIRK_FIX_ASYN_XFER_ALWAYS)!=0)
32839217Sgibbs				adv->fix_asyn_xfer_always |= target_mask;
32939217Sgibbs			else
33039217Sgibbs				adv->fix_asyn_xfer_always &= ~target_mask;
33139217Sgibbs			/*
33239217Sgibbs			 * We start out life with all bits set and clear them
33339217Sgibbs			 * after we've determined that the fix isn't necessary.
33439217Sgibbs			 * It may well be that we've already cleared a target
33539217Sgibbs			 * before the full inquiry session completes, so don't
33639217Sgibbs			 * gratuitously set a target bit even if it has this
33739217Sgibbs			 * quirk.  But, if the quirk exonerates a device, clear
33839217Sgibbs			 * the bit now.
33939217Sgibbs			 */
34039217Sgibbs			if ((entry->quirks & ADV_QUIRK_FIX_ASYN_XFER) == 0)
34139217Sgibbs				adv->fix_asyn_xfer &= ~target_mask;
34239217Sgibbs		}
34339217Sgibbs		/*
34439217Sgibbs		 * Reset our sync settings now that we've determined
34539217Sgibbs		 * what quirks are in effect for the device.
34639217Sgibbs		 */
34739217Sgibbs		tinfo = &adv->tinfo[cgd->ccb_h.target_id];
34839217Sgibbs		adv_set_syncrate(adv, cgd->ccb_h.path,
34939217Sgibbs				 cgd->ccb_h.target_id,
35039217Sgibbs				 tinfo->current.period,
35139217Sgibbs				 tinfo->current.offset,
35239217Sgibbs				 ADV_TRANS_CUR);
35339217Sgibbs		break;
35439217Sgibbs	}
35539217Sgibbs	case AC_LOST_DEVICE:
35639217Sgibbs	{
35739217Sgibbs		u_int target_mask;
35839217Sgibbs
35939217Sgibbs		if (adv->bug_fix_control & ADV_BUG_FIX_ASYN_USE_SYN) {
36039217Sgibbs			target_mask = 0x01 << xpt_path_target_id(path);
36139217Sgibbs			adv->fix_asyn_xfer |= target_mask;
36239217Sgibbs		}
36339217Sgibbs
36439217Sgibbs		/*
36539217Sgibbs		 * Revert to async transfers
36639217Sgibbs		 * for the next device.
36739217Sgibbs		 */
36839217Sgibbs		adv_set_syncrate(adv, /*path*/NULL,
36939217Sgibbs				 xpt_path_target_id(path),
37039217Sgibbs				 /*period*/0,
37139217Sgibbs				 /*offset*/0,
37239217Sgibbs				 ADV_TRANS_GOAL|ADV_TRANS_CUR);
37339217Sgibbs	}
37439217Sgibbs	default:
37539217Sgibbs		break;
37639217Sgibbs	}
37739217Sgibbs}
37839217Sgibbs
37939217Sgibbsvoid
38039217Sgibbsadv_set_bank(struct adv_softc *adv, u_int8_t bank)
38118781Sgibbs{
38239217Sgibbs	u_int8_t control;
38339217Sgibbs
38439217Sgibbs	/*
38539217Sgibbs	 * Start out with the bank reset to 0
38639217Sgibbs	 */
38739217Sgibbs	control = ADV_INB(adv, ADV_CHIP_CTRL)
38839217Sgibbs		  &  (~(ADV_CC_SINGLE_STEP | ADV_CC_TEST
38939217Sgibbs			| ADV_CC_DIAG | ADV_CC_SCSI_RESET
39039217Sgibbs			| ADV_CC_CHIP_RESET | ADV_CC_BANK_ONE));
39139217Sgibbs	if (bank == 1) {
39239217Sgibbs		control |= ADV_CC_BANK_ONE;
39339217Sgibbs	} else if (bank == 2) {
39439217Sgibbs		control |= ADV_CC_DIAG | ADV_CC_BANK_ONE;
39539217Sgibbs	}
39639217Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, control);
39739217Sgibbs}
39839217Sgibbs
39939217Sgibbsu_int8_t
40039217Sgibbsadv_read_lram_8(struct adv_softc *adv, u_int16_t addr)
40139217Sgibbs{
40218781Sgibbs	u_int8_t   byte_data;
40318781Sgibbs	u_int16_t  word_data;
40418781Sgibbs
40518781Sgibbs	/*
40618781Sgibbs	 * LRAM is accessed on 16bit boundaries.
40718781Sgibbs	 */
40818781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr & 0xFFFE);
40918781Sgibbs	word_data = ADV_INW(adv, ADV_LRAM_DATA);
41018781Sgibbs	if (addr & 1) {
41118781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
41218781Sgibbs		byte_data = (u_int8_t)(word_data & 0xFF);
41318781Sgibbs#else
41418781Sgibbs		byte_data = (u_int8_t)((word_data >> 8) & 0xFF);
41518781Sgibbs#endif
41618781Sgibbs	} else {
41718781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
41818781Sgibbs		byte_data = (u_int8_t)((word_data >> 8) & 0xFF);
41918781Sgibbs#else
42018781Sgibbs		byte_data = (u_int8_t)(word_data & 0xFF);
42118781Sgibbs#endif
42218781Sgibbs	}
42318781Sgibbs	return (byte_data);
42418781Sgibbs}
42518781Sgibbs
42618781Sgibbsvoid
42739217Sgibbsadv_write_lram_8(struct adv_softc *adv, u_int16_t addr, u_int8_t value)
42818781Sgibbs{
42918781Sgibbs	u_int16_t word_data;
43018781Sgibbs
43118781Sgibbs	word_data = adv_read_lram_16(adv, addr & 0xFFFE);
43218781Sgibbs	if (addr & 1) {
43318781Sgibbs		word_data &= 0x00FF;
43418781Sgibbs		word_data |= (((u_int8_t)value << 8) & 0xFF00);
43518781Sgibbs	} else {
43618781Sgibbs		word_data &= 0xFF00;
43718781Sgibbs		word_data |= ((u_int8_t)value & 0x00FF);
43818781Sgibbs	}
43918781Sgibbs	adv_write_lram_16(adv, addr & 0xFFFE, word_data);
44018781Sgibbs}
44118781Sgibbs
44218781Sgibbs
44318781Sgibbsu_int16_t
44439217Sgibbsadv_read_lram_16(struct adv_softc *adv, u_int16_t addr)
44518781Sgibbs{
44618781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
44718781Sgibbs	return (ADV_INW(adv, ADV_LRAM_DATA));
44818781Sgibbs}
44918781Sgibbs
45018781Sgibbsvoid
45139217Sgibbsadv_write_lram_16(struct adv_softc *adv, u_int16_t addr, u_int16_t value)
45218781Sgibbs{
45318781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
45418781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, value);
45518781Sgibbs}
45618781Sgibbs
45718781Sgibbs/*
45839217Sgibbs * Determine if there is a board at "iobase" by looking
45939217Sgibbs * for the AdvanSys signatures.  Return 1 if a board is
46039217Sgibbs * found, 0 otherwise.
46118781Sgibbs */
46239217Sgibbsint
46339217Sgibbsadv_find_signature(bus_space_tag_t tag, bus_space_handle_t bsh)
46439217Sgibbs{
46539217Sgibbs	u_int16_t signature;
46639217Sgibbs
46739217Sgibbs	if (bus_space_read_1(tag, bsh, ADV_SIGNATURE_BYTE) == ADV_1000_ID1B) {
46839217Sgibbs		signature = bus_space_read_2(tag, bsh, ADV_SIGNATURE_WORD);
46939217Sgibbs		if ((signature == ADV_1000_ID0W)
47039217Sgibbs		 || (signature == ADV_1000_ID0W_FIX))
47139217Sgibbs			return (1);
47239217Sgibbs	}
47339217Sgibbs	return (0);
47439217Sgibbs}
47539217Sgibbs
47618781Sgibbsvoid
47739217Sgibbsadv_lib_init(struct adv_softc *adv)
47818781Sgibbs{
47939217Sgibbs	if ((adv->type & ADV_ULTRA) != 0) {
48039217Sgibbs		adv->sdtr_period_tbl = adv_sdtr_period_tbl_ultra;
48139217Sgibbs		adv->sdtr_period_tbl_size = sizeof(adv_sdtr_period_tbl_ultra);
48239217Sgibbs	} else {
48339217Sgibbs		adv->sdtr_period_tbl = adv_sdtr_period_tbl;
48439217Sgibbs		adv->sdtr_period_tbl_size = sizeof(adv_sdtr_period_tbl);
48539217Sgibbs	}
48618781Sgibbs}
48718781Sgibbs
48818781Sgibbsu_int16_t
48939217Sgibbsadv_get_eeprom_config(struct adv_softc *adv, struct
49039217Sgibbs		      adv_eeprom_config  *eeprom_config)
49118781Sgibbs{
49218781Sgibbs	u_int16_t	sum;
49318781Sgibbs	u_int16_t	*wbuf;
49418781Sgibbs	u_int8_t	cfg_beg;
49518781Sgibbs	u_int8_t	cfg_end;
49618781Sgibbs	u_int8_t	s_addr;
49718781Sgibbs
49818781Sgibbs	wbuf = (u_int16_t *)eeprom_config;
49918781Sgibbs	sum = 0;
50018781Sgibbs
50118781Sgibbs	for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
50218781Sgibbs		*wbuf = adv_read_eeprom_16(adv, s_addr);
50318781Sgibbs		sum += *wbuf;
50418781Sgibbs	}
50518781Sgibbs
50618781Sgibbs	if (adv->type & ADV_VL) {
50718781Sgibbs		cfg_beg = ADV_EEPROM_CFG_BEG_VL;
50818781Sgibbs		cfg_end = ADV_EEPROM_MAX_ADDR_VL;
50918781Sgibbs	} else {
51018781Sgibbs		cfg_beg = ADV_EEPROM_CFG_BEG;
51118781Sgibbs		cfg_end = ADV_EEPROM_MAX_ADDR;
51218781Sgibbs	}
51318781Sgibbs
51418781Sgibbs	for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
51518781Sgibbs		*wbuf = adv_read_eeprom_16(adv, s_addr);
51618781Sgibbs		sum += *wbuf;
517153072Sru#ifdef ADV_DEBUG_EEPROM
51818781Sgibbs		printf("Addr 0x%x: 0x%04x\n", s_addr, *wbuf);
51918781Sgibbs#endif
52018781Sgibbs	}
52118781Sgibbs	*wbuf = adv_read_eeprom_16(adv, s_addr);
52218781Sgibbs	return (sum);
52318781Sgibbs}
52418781Sgibbs
52518781Sgibbsint
52639217Sgibbsadv_set_eeprom_config(struct adv_softc *adv,
52739217Sgibbs		      struct adv_eeprom_config *eeprom_config)
52818781Sgibbs{
52918781Sgibbs	int	retry;
53018781Sgibbs
53118781Sgibbs	retry = 0;
53218781Sgibbs	while (1) {
53318781Sgibbs		if (adv_set_eeprom_config_once(adv, eeprom_config) == 0) {
53418781Sgibbs			break;
53518781Sgibbs		}
53618781Sgibbs		if (++retry > ADV_EEPROM_MAX_RETRY) {
53718781Sgibbs			break;
53818781Sgibbs		}
53918781Sgibbs	}
54018781Sgibbs	return (retry > ADV_EEPROM_MAX_RETRY);
54118781Sgibbs}
54218781Sgibbs
54318781Sgibbsint
54455945Sgibbsadv_reset_chip(struct adv_softc *adv, int reset_bus)
54518781Sgibbs{
54618781Sgibbs	adv_stop_chip(adv);
54755945Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_CHIP_RESET | ADV_CC_HALT
54855945Sgibbs				     | (reset_bus ? ADV_CC_SCSI_RESET : 0));
54955945Sgibbs	DELAY(60);
55018781Sgibbs
55118781Sgibbs	adv_set_chip_ih(adv, ADV_INS_RFLAG_WTM);
55218781Sgibbs	adv_set_chip_ih(adv, ADV_INS_HALT);
55318781Sgibbs
55455945Sgibbs	if (reset_bus)
55555945Sgibbs		ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_CHIP_RESET | ADV_CC_HALT);
55655945Sgibbs
55718781Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT);
55855945Sgibbs	if (reset_bus)
55955945Sgibbs		DELAY(200 * 1000);
56055945Sgibbs
56155945Sgibbs	ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_CLR_SCSI_RESET_INT);
56255945Sgibbs	ADV_OUTW(adv, ADV_CHIP_STATUS, 0);
56318781Sgibbs	return (adv_is_chip_halted(adv));
56418781Sgibbs}
56518781Sgibbs
56618781Sgibbsint
56739217Sgibbsadv_test_external_lram(struct adv_softc* adv)
56818781Sgibbs{
56918781Sgibbs	u_int16_t	q_addr;
57018781Sgibbs	u_int16_t	saved_value;
57118781Sgibbs	int		success;
57218781Sgibbs
57318781Sgibbs	success = 0;
57418781Sgibbs
57518781Sgibbs	q_addr = ADV_QNO_TO_QADDR(241);
57618781Sgibbs	saved_value = adv_read_lram_16(adv, q_addr);
57718781Sgibbs	if (adv_write_and_verify_lram_16(adv, q_addr, 0x55AA) == 0) {
57818781Sgibbs		success = 1;
57918781Sgibbs		adv_write_lram_16(adv, q_addr, saved_value);
58018781Sgibbs	}
58118781Sgibbs	return (success);
58218781Sgibbs}
58318781Sgibbs
58418781Sgibbs
58518781Sgibbsint
58639217Sgibbsadv_init_lram_and_mcode(struct adv_softc *adv)
58718781Sgibbs{
58818781Sgibbs	u_int32_t	retval;
58939217Sgibbs
59018781Sgibbs	adv_disable_interrupt(adv);
59118781Sgibbs
59218781Sgibbs	adv_init_lram(adv);
59318781Sgibbs
59439217Sgibbs	retval = adv_load_microcode(adv, 0, (u_int16_t *)adv_mcode,
59539217Sgibbs				    adv_mcode_size);
59618781Sgibbs	if (retval != adv_mcode_chksum) {
59718781Sgibbs		printf("adv%d: Microcode download failed checksum!\n",
59818781Sgibbs		       adv->unit);
59918781Sgibbs		return (1);
60018781Sgibbs	}
60118781Sgibbs
60218781Sgibbs	if (adv_init_microcode_var(adv) != 0)
60318781Sgibbs		return (1);
60418781Sgibbs
60518781Sgibbs	adv_enable_interrupt(adv);
60618781Sgibbs	return (0);
60718781Sgibbs}
60818781Sgibbs
60918781Sgibbsu_int8_t
61039217Sgibbsadv_get_chip_irq(struct adv_softc *adv)
61118781Sgibbs{
61218781Sgibbs	u_int16_t	cfg_lsw;
61318781Sgibbs	u_int8_t	chip_irq;
61418781Sgibbs
61518781Sgibbs	cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW);
61618781Sgibbs
61718781Sgibbs	if ((adv->type & ADV_VL) != 0) {
61818781Sgibbs		chip_irq = (u_int8_t)(((cfg_lsw >> 2) & 0x07));
61918781Sgibbs		if ((chip_irq == 0) ||
62018781Sgibbs		    (chip_irq == 4) ||
62118781Sgibbs		    (chip_irq == 7)) {
62218781Sgibbs			return (0);
62318781Sgibbs		}
62418781Sgibbs		return (chip_irq + (ADV_MIN_IRQ_NO - 1));
62518781Sgibbs	}
62618781Sgibbs	chip_irq = (u_int8_t)(((cfg_lsw >> 2) & 0x03));
62718781Sgibbs	if (chip_irq == 3)
62818781Sgibbs		chip_irq += 2;
62918781Sgibbs	return (chip_irq + ADV_MIN_IRQ_NO);
63018781Sgibbs}
63118781Sgibbs
63218781Sgibbsu_int8_t
63339217Sgibbsadv_set_chip_irq(struct adv_softc *adv, u_int8_t irq_no)
63418781Sgibbs{
63518781Sgibbs	u_int16_t	cfg_lsw;
63618781Sgibbs
63718781Sgibbs	if ((adv->type & ADV_VL) != 0) {
63818781Sgibbs		if (irq_no != 0) {
63939217Sgibbs			if ((irq_no < ADV_MIN_IRQ_NO)
64039217Sgibbs			 || (irq_no > ADV_MAX_IRQ_NO)) {
64118781Sgibbs				irq_no = 0;
64218781Sgibbs			} else {
64318781Sgibbs				irq_no -= ADV_MIN_IRQ_NO - 1;
64418781Sgibbs			}
64518781Sgibbs		}
64618781Sgibbs		cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFE3;
64718781Sgibbs		cfg_lsw |= 0x0010;
64818781Sgibbs		ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw);
64918781Sgibbs		adv_toggle_irq_act(adv);
65018781Sgibbs
65118781Sgibbs		cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFE0;
65218781Sgibbs		cfg_lsw |= (irq_no & 0x07) << 2;
65318781Sgibbs		ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw);
65418781Sgibbs		adv_toggle_irq_act(adv);
65518781Sgibbs	} else if ((adv->type & ADV_ISA) != 0) {
65618781Sgibbs		if (irq_no == 15)
65718781Sgibbs			irq_no -= 2;
65818781Sgibbs		irq_no -= ADV_MIN_IRQ_NO;
65918781Sgibbs		cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW) & 0xFFF3;
66018781Sgibbs		cfg_lsw |= (irq_no & 0x03) << 2;
66118781Sgibbs		ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw);
66218781Sgibbs	}
66318781Sgibbs	return (adv_get_chip_irq(adv));
66418781Sgibbs}
66518781Sgibbs
66639217Sgibbsvoid
66739217Sgibbsadv_set_chip_scsiid(struct adv_softc *adv, int new_id)
66839217Sgibbs{
66939217Sgibbs	u_int16_t cfg_lsw;
67039217Sgibbs
67139217Sgibbs	cfg_lsw = ADV_INW(adv, ADV_CONFIG_LSW);
67239217Sgibbs	if (ADV_CONFIG_SCSIID(cfg_lsw) == new_id)
67339217Sgibbs		return;
67439217Sgibbs    	cfg_lsw &= ~ADV_CFG_LSW_SCSIID;
67539217Sgibbs	cfg_lsw |= (new_id & ADV_MAX_TID) << ADV_CFG_LSW_SCSIID_SHIFT;
67639217Sgibbs	ADV_OUTW(adv, ADV_CONFIG_LSW, cfg_lsw);
67739217Sgibbs}
67839217Sgibbs
67918781Sgibbsint
68039217Sgibbsadv_execute_scsi_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq,
68139217Sgibbs		       u_int32_t datalen)
68218781Sgibbs{
68339217Sgibbs	struct		adv_target_transinfo* tinfo;
68439217Sgibbs	u_int32_t	*p_data_addr;
68539217Sgibbs	u_int32_t	*p_data_bcount;
68639217Sgibbs	int		disable_syn_offset_one_fix;
68718781Sgibbs	int		retval;
68818781Sgibbs	u_int		n_q_required;
68918781Sgibbs	u_int32_t	addr;
69018781Sgibbs	u_int8_t	sg_entry_cnt;
69118781Sgibbs	u_int8_t	target_ix;
69218781Sgibbs	u_int8_t	sg_entry_cnt_minus_one;
69318781Sgibbs	u_int8_t	tid_no;
69418781Sgibbs
69518781Sgibbs	scsiq->q1.q_no = 0;
69618781Sgibbs	retval = 1;  /* Default to error case */
69718781Sgibbs	target_ix = scsiq->q2.target_ix;
69818781Sgibbs	tid_no = ADV_TIX_TO_TID(target_ix);
69939217Sgibbs	tinfo = &adv->tinfo[tid_no];
70018781Sgibbs
70139217Sgibbs	if (scsiq->cdbptr[0] == REQUEST_SENSE) {
70239217Sgibbs		/* Renegotiate if appropriate. */
70339217Sgibbs		adv_set_syncrate(adv, /*struct cam_path */NULL,
70439217Sgibbs				 tid_no, /*period*/0, /*offset*/0,
70539217Sgibbs				 ADV_TRANS_CUR);
70639217Sgibbs		if (tinfo->current.period != tinfo->goal.period) {
70739217Sgibbs			adv_msgout_sdtr(adv, tinfo->goal.period,
70839217Sgibbs					tinfo->goal.offset);
70918781Sgibbs			scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
71018781Sgibbs		}
71118781Sgibbs	}
71218781Sgibbs
71318781Sgibbs	if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
71418781Sgibbs		sg_entry_cnt = scsiq->sg_head->entry_cnt;
71518781Sgibbs		sg_entry_cnt_minus_one = sg_entry_cnt - 1;
71618781Sgibbs
71718781Sgibbs#ifdef DIAGNOSTIC
71818781Sgibbs		if (sg_entry_cnt <= 1)
71939217Sgibbs			panic("adv_execute_scsi_queue: Queue "
72039217Sgibbs			      "with QC_SG_HEAD set but %d segs.", sg_entry_cnt);
72118781Sgibbs
72218781Sgibbs		if (sg_entry_cnt > ADV_MAX_SG_LIST)
72339217Sgibbs			panic("adv_execute_scsi_queue: "
72439217Sgibbs			      "Queue with too many segs.");
72518781Sgibbs
72655945Sgibbs		if ((adv->type & (ADV_ISA | ADV_VL | ADV_EISA)) != 0) {
72739505Sgibbs			int i;
72839505Sgibbs
72918781Sgibbs			for (i = 0; i < sg_entry_cnt_minus_one; i++) {
73018781Sgibbs				addr = scsiq->sg_head->sg_list[i].addr +
73118781Sgibbs				       scsiq->sg_head->sg_list[i].bytes;
73218781Sgibbs
73318781Sgibbs				if ((addr & 0x0003) != 0)
73439217Sgibbs					panic("adv_execute_scsi_queue: SG "
73539217Sgibbs					      "with odd address or byte count");
73618781Sgibbs			}
73718781Sgibbs		}
73818781Sgibbs#endif
73939217Sgibbs		p_data_addr =
74039217Sgibbs		    &scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].addr;
74139217Sgibbs		p_data_bcount =
74239217Sgibbs		    &scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].bytes;
74318781Sgibbs
74418781Sgibbs		n_q_required = adv_sgcount_to_qcount(sg_entry_cnt);
74518781Sgibbs		scsiq->sg_head->queue_cnt = n_q_required - 1;
74618781Sgibbs	} else {
74718781Sgibbs		p_data_addr = &scsiq->q1.data_addr;
74818781Sgibbs		p_data_bcount = &scsiq->q1.data_cnt;
74918781Sgibbs		n_q_required = 1;
75018781Sgibbs	}
75118781Sgibbs
75239217Sgibbs	disable_syn_offset_one_fix = FALSE;
75339217Sgibbs
75439217Sgibbs	if ((adv->fix_asyn_xfer & scsiq->q1.target_id) != 0
75539217Sgibbs	 && (adv->fix_asyn_xfer_always & scsiq->q1.target_id) == 0) {
75639217Sgibbs
75739217Sgibbs		if (datalen != 0) {
75839217Sgibbs			if (datalen < 512) {
75939217Sgibbs				disable_syn_offset_one_fix = TRUE;
76039217Sgibbs			} else {
76139217Sgibbs				if (scsiq->cdbptr[0] == INQUIRY
76239217Sgibbs				 || scsiq->cdbptr[0] == REQUEST_SENSE
76339217Sgibbs				 || scsiq->cdbptr[0] == READ_CAPACITY
76439217Sgibbs				 || scsiq->cdbptr[0] == MODE_SELECT_6
76539217Sgibbs				 || scsiq->cdbptr[0] == MODE_SENSE_6
76639217Sgibbs				 || scsiq->cdbptr[0] == MODE_SENSE_10
76739217Sgibbs				 || scsiq->cdbptr[0] == MODE_SELECT_10
76839217Sgibbs				 || scsiq->cdbptr[0] == READ_TOC) {
76939217Sgibbs					disable_syn_offset_one_fix = TRUE;
77018781Sgibbs				}
77118781Sgibbs			}
77218781Sgibbs		}
77318781Sgibbs	}
77439217Sgibbs
77539217Sgibbs	if (disable_syn_offset_one_fix) {
77639217Sgibbs		scsiq->q2.tag_code &=
77739217Sgibbs		    ~(MSG_SIMPLE_Q_TAG|MSG_HEAD_OF_Q_TAG|MSG_ORDERED_Q_TAG);
77839217Sgibbs		scsiq->q2.tag_code |= (ADV_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX
77939217Sgibbs				     | ADV_TAG_FLAG_DISABLE_DISCONNECT);
78039217Sgibbs	}
78139217Sgibbs
78239217Sgibbs	if ((adv->bug_fix_control & ADV_BUG_FIX_IF_NOT_DWB) != 0
78339217Sgibbs	 && (scsiq->cdbptr[0] == READ_10 || scsiq->cdbptr[0] == READ_6)) {
78439217Sgibbs		u_int8_t extra_bytes;
78539217Sgibbs
78639217Sgibbs		addr = *p_data_addr + *p_data_bcount;
78739217Sgibbs		extra_bytes = addr & 0x0003;
78839217Sgibbs		if (extra_bytes != 0
78939217Sgibbs		 && ((scsiq->q1.cntl & QC_SG_HEAD) != 0
79039217Sgibbs		  || (scsiq->q1.data_cnt & 0x01FF) == 0)) {
79139217Sgibbs			scsiq->q2.tag_code |= ADV_TAG_FLAG_EXTRA_BYTES;
79239217Sgibbs			scsiq->q1.extra_bytes = extra_bytes;
79339217Sgibbs			*p_data_bcount -= extra_bytes;
79439217Sgibbs		}
79539217Sgibbs	}
79639217Sgibbs
79718781Sgibbs	if ((adv_get_num_free_queues(adv, n_q_required) >= n_q_required)
79839217Sgibbs	 || ((scsiq->q1.cntl & QC_URGENT) != 0))
79918781Sgibbs		retval = adv_send_scsi_queue(adv, scsiq, n_q_required);
80018781Sgibbs
80118781Sgibbs	return (retval);
80218781Sgibbs}
80318781Sgibbs
80418781Sgibbs
80518781Sgibbsu_int8_t
80639217Sgibbsadv_copy_lram_doneq(struct adv_softc *adv, u_int16_t q_addr,
80739217Sgibbs		    struct adv_q_done_info *scsiq, u_int32_t max_dma_count)
80818781Sgibbs{
80939217Sgibbs	u_int16_t val;
81039217Sgibbs	u_int8_t  sg_queue_cnt;
81118781Sgibbs
81218781Sgibbs	adv_get_q_info(adv, q_addr + ADV_SCSIQ_DONE_INFO_BEG,
81318781Sgibbs		       (u_int16_t *)scsiq,
81418781Sgibbs		       (sizeof(scsiq->d2) + sizeof(scsiq->d3)) / 2);
81518781Sgibbs
81618781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
81718781Sgibbs	adv_adj_endian_qdone_info(scsiq);
81818781Sgibbs#endif
81918781Sgibbs
82018781Sgibbs	val = adv_read_lram_16(adv, q_addr + ADV_SCSIQ_B_STATUS);
82118781Sgibbs	scsiq->q_status = val & 0xFF;
82218781Sgibbs	scsiq->q_no = (val >> 8) & 0XFF;
82318781Sgibbs
82418781Sgibbs	val = adv_read_lram_16(adv, q_addr + ADV_SCSIQ_B_CNTL);
82518781Sgibbs	scsiq->cntl = val & 0xFF;
82618781Sgibbs	sg_queue_cnt = (val >> 8) & 0xFF;
82718781Sgibbs
82818781Sgibbs	val = adv_read_lram_16(adv,q_addr + ADV_SCSIQ_B_SENSE_LEN);
82918781Sgibbs	scsiq->sense_len = val & 0xFF;
83039217Sgibbs	scsiq->extra_bytes = (val >> 8) & 0xFF;
83118781Sgibbs
83240133Sgibbs	/*
83355945Sgibbs	 * Due to a bug in accessing LRAM on the 940UA, the residual
83455945Sgibbs	 * is split into separate high and low 16bit quantities.
83540133Sgibbs	 */
83639217Sgibbs	scsiq->remain_bytes =
83740133Sgibbs	    adv_read_lram_16(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_CNT);
83855945Sgibbs	scsiq->remain_bytes |=
83955945Sgibbs	    adv_read_lram_16(adv, q_addr + ADV_SCSIQ_W_ALT_DC1) << 16;
84055945Sgibbs
84118781Sgibbs	/*
84218781Sgibbs	 * XXX Is this just a safeguard or will the counter really
84318781Sgibbs	 * have bogus upper bits?
84418781Sgibbs	 */
84518781Sgibbs	scsiq->remain_bytes &= max_dma_count;
84618781Sgibbs
84718781Sgibbs	return (sg_queue_cnt);
84818781Sgibbs}
84918781Sgibbs
85018781Sgibbsint
85139217Sgibbsadv_start_chip(struct adv_softc *adv)
85218781Sgibbs{
85339217Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, 0);
85439217Sgibbs	if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) != 0)
85539217Sgibbs		return (0);
85639217Sgibbs	return (1);
85739217Sgibbs}
85839217Sgibbs
85939217Sgibbsint
86039217Sgibbsadv_stop_execution(struct adv_softc *adv)
86139217Sgibbs{
86218781Sgibbs	int count;
86318781Sgibbs
86418781Sgibbs	count = 0;
86518781Sgibbs	if (adv_read_lram_8(adv, ADV_STOP_CODE_B) == 0) {
86618781Sgibbs		adv_write_lram_8(adv, ADV_STOP_CODE_B,
86718781Sgibbs				 ADV_STOP_REQ_RISC_STOP);
86818781Sgibbs		do {
86918781Sgibbs			if (adv_read_lram_8(adv, ADV_STOP_CODE_B) &
87018781Sgibbs				ADV_STOP_ACK_RISC_STOP) {
87118781Sgibbs				return (1);
87218781Sgibbs			}
87318781Sgibbs			DELAY(1000);
87418781Sgibbs		} while (count++ < 20);
87518781Sgibbs	}
87618781Sgibbs	return (0);
87718781Sgibbs}
87818781Sgibbs
87918781Sgibbsint
88039217Sgibbsadv_is_chip_halted(struct adv_softc *adv)
88118781Sgibbs{
88218781Sgibbs	if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) != 0) {
88318781Sgibbs		if ((ADV_INB(adv, ADV_CHIP_CTRL) & ADV_CC_HALT) != 0) {
88418781Sgibbs			return (1);
88518781Sgibbs		}
88618781Sgibbs	}
88718781Sgibbs	return (0);
88818781Sgibbs}
88918781Sgibbs
89018781Sgibbs/*
89118781Sgibbs * XXX The numeric constants and the loops in this routine
89218781Sgibbs * need to be documented.
89318781Sgibbs */
89418781Sgibbsvoid
89539217Sgibbsadv_ack_interrupt(struct adv_softc *adv)
89618781Sgibbs{
89718781Sgibbs	u_int8_t	host_flag;
89818781Sgibbs	u_int8_t	risc_flag;
89918781Sgibbs	int		loop;
90018781Sgibbs
90118781Sgibbs	loop = 0;
90218781Sgibbs	do {
90318781Sgibbs		risc_flag = adv_read_lram_8(adv, ADVV_RISC_FLAG_B);
90418781Sgibbs		if (loop++ > 0x7FFF) {
90518781Sgibbs			break;
90618781Sgibbs		}
90718781Sgibbs	} while ((risc_flag & ADV_RISC_FLAG_GEN_INT) != 0);
90818781Sgibbs
90918781Sgibbs	host_flag = adv_read_lram_8(adv, ADVV_HOST_FLAG_B);
91018781Sgibbs	adv_write_lram_8(adv, ADVV_HOST_FLAG_B,
91118781Sgibbs			 host_flag | ADV_HOST_FLAG_ACK_INT);
91218781Sgibbs
91318781Sgibbs	ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_INT_ACK);
91418781Sgibbs	loop = 0;
91518781Sgibbs	while (ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_INT_PENDING) {
91618781Sgibbs		ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_INT_ACK);
91718781Sgibbs		if (loop++ > 3) {
91818781Sgibbs			break;
91918781Sgibbs		}
92018781Sgibbs	}
92118781Sgibbs
92218781Sgibbs	adv_write_lram_8(adv, ADVV_HOST_FLAG_B, host_flag);
92318781Sgibbs}
92418781Sgibbs
92518781Sgibbs/*
92618781Sgibbs * Handle all conditions that may halt the chip waiting
92718781Sgibbs * for us to intervene.
92818781Sgibbs */
92918781Sgibbsvoid
93039217Sgibbsadv_isr_chip_halted(struct adv_softc *adv)
93118781Sgibbs{
93218781Sgibbs	u_int16_t	  int_halt_code;
93339217Sgibbs	u_int16_t	  halt_q_addr;
93439217Sgibbs	target_bit_vector target_mask;
93539217Sgibbs	target_bit_vector scsi_busy;
93618781Sgibbs	u_int8_t	  halt_qp;
93718781Sgibbs	u_int8_t	  target_ix;
93818781Sgibbs	u_int8_t	  q_cntl;
93918781Sgibbs	u_int8_t	  tid_no;
94018781Sgibbs
94118781Sgibbs	int_halt_code = adv_read_lram_16(adv, ADVV_HALTCODE_W);
94218781Sgibbs	halt_qp = adv_read_lram_8(adv, ADVV_CURCDB_B);
94318781Sgibbs	halt_q_addr = ADV_QNO_TO_QADDR(halt_qp);
94418781Sgibbs	target_ix = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_TARGET_IX);
94518781Sgibbs	q_cntl = adv_read_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL);
94618781Sgibbs	tid_no = ADV_TIX_TO_TID(target_ix);
94739217Sgibbs	target_mask = ADV_TID_TO_TARGET_MASK(tid_no);
94839217Sgibbs	if (int_halt_code == ADV_HALT_DISABLE_ASYN_USE_SYN_FIX) {
94918781Sgibbs		/*
95039217Sgibbs		 * Temporarily disable the async fix by removing
95139217Sgibbs		 * this target from the list of affected targets,
95239217Sgibbs		 * setting our async rate, and then putting us
95339217Sgibbs		 * back into the mask.
95418781Sgibbs		 */
95539217Sgibbs		adv->fix_asyn_xfer &= ~target_mask;
95639217Sgibbs		adv_set_syncrate(adv, /*struct cam_path */NULL,
95739217Sgibbs				 tid_no, /*period*/0, /*offset*/0,
95839217Sgibbs				 ADV_TRANS_ACTIVE);
95939217Sgibbs		adv->fix_asyn_xfer |= target_mask;
96039217Sgibbs	} else if (int_halt_code == ADV_HALT_ENABLE_ASYN_USE_SYN_FIX) {
96139217Sgibbs		adv_set_syncrate(adv, /*struct cam_path */NULL,
96239217Sgibbs				 tid_no, /*period*/0, /*offset*/0,
96339217Sgibbs				 ADV_TRANS_ACTIVE);
96439217Sgibbs	} else if (int_halt_code == ADV_HALT_EXTMSG_IN) {
96539217Sgibbs		adv_handle_extmsg_in(adv, halt_q_addr, q_cntl,
96639217Sgibbs				     target_mask, tid_no);
96718781Sgibbs	} else if (int_halt_code == ADV_HALT_CHK_CONDITION) {
96855945Sgibbs		struct	  adv_target_transinfo* tinfo;
96955945Sgibbs		union	  ccb *ccb;
97055945Sgibbs		u_int32_t cinfo_index;
97155945Sgibbs		u_int8_t  tag_code;
97255945Sgibbs		u_int8_t  q_status;
97318781Sgibbs
97439217Sgibbs		tinfo = &adv->tinfo[tid_no];
97518781Sgibbs		q_cntl |= QC_REQ_SENSE;
97618781Sgibbs
97739217Sgibbs		/* Renegotiate if appropriate. */
97839217Sgibbs		adv_set_syncrate(adv, /*struct cam_path */NULL,
97939217Sgibbs				 tid_no, /*period*/0, /*offset*/0,
98039217Sgibbs				 ADV_TRANS_CUR);
98139217Sgibbs		if (tinfo->current.period != tinfo->goal.period) {
98239217Sgibbs			adv_msgout_sdtr(adv, tinfo->goal.period,
98339217Sgibbs					tinfo->goal.offset);
98418781Sgibbs			q_cntl |= QC_MSG_OUT;
98518781Sgibbs		}
98618781Sgibbs		adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl);
98718781Sgibbs
98818781Sgibbs		/* Don't tag request sense commands */
98939217Sgibbs		tag_code = adv_read_lram_8(adv,
99039217Sgibbs					   halt_q_addr + ADV_SCSIQ_B_TAG_CODE);
99139217Sgibbs		tag_code &=
99239217Sgibbs		    ~(MSG_SIMPLE_Q_TAG|MSG_HEAD_OF_Q_TAG|MSG_ORDERED_Q_TAG);
99318781Sgibbs
99439217Sgibbs		if ((adv->fix_asyn_xfer & target_mask) != 0
99539217Sgibbs		 && (adv->fix_asyn_xfer_always & target_mask) == 0) {
99639217Sgibbs			tag_code |= (ADV_TAG_FLAG_DISABLE_DISCONNECT
99739217Sgibbs				 | ADV_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
99839217Sgibbs		}
99939217Sgibbs		adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_TAG_CODE,
100039217Sgibbs				 tag_code);
100139217Sgibbs		q_status = adv_read_lram_8(adv,
100239217Sgibbs					   halt_q_addr + ADV_SCSIQ_B_STATUS);
100318781Sgibbs		q_status |= (QS_READY | QS_BUSY);
100439217Sgibbs		adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_STATUS,
100539217Sgibbs				 q_status);
100639217Sgibbs		/*
100739217Sgibbs		 * Freeze the devq until we can handle the sense condition.
100839217Sgibbs		 */
100955945Sgibbs		cinfo_index =
101055945Sgibbs		    adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX);
101155945Sgibbs		ccb = adv->ccb_infos[cinfo_index].ccb;
101239217Sgibbs		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
101339217Sgibbs		ccb->ccb_h.status |= CAM_DEV_QFRZN;
101439217Sgibbs		adv_abort_ccb(adv, tid_no, ADV_TIX_TO_LUN(target_ix),
101539217Sgibbs			      /*ccb*/NULL, CAM_REQUEUE_REQ,
101639217Sgibbs			      /*queued_only*/TRUE);
101718781Sgibbs		scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B);
101839217Sgibbs		scsi_busy &= ~target_mask;
101918781Sgibbs		adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy);
102045846Sgibbs		/*
102145846Sgibbs		 * Ensure we have enough time to actually
102245846Sgibbs		 * retrieve the sense.
102345846Sgibbs		 */
102445846Sgibbs		untimeout(adv_timeout, (caddr_t)ccb, ccb->ccb_h.timeout_ch);
102545846Sgibbs		ccb->ccb_h.timeout_ch =
102645846Sgibbs		    timeout(adv_timeout, (caddr_t)ccb, 5 * hz);
102718781Sgibbs	} else if (int_halt_code == ADV_HALT_SDTR_REJECTED) {
102839217Sgibbs		struct	ext_msg out_msg;
102918781Sgibbs
103018781Sgibbs		adv_read_lram_16_multi(adv, ADVV_MSGOUT_BEG,
103118781Sgibbs				       (u_int16_t *) &out_msg,
103218781Sgibbs				       sizeof(out_msg)/2);
103318781Sgibbs
103439217Sgibbs		if ((out_msg.msg_type == MSG_EXTENDED)
103539217Sgibbs		 && (out_msg.msg_len == MSG_EXT_SDTR_LEN)
103639217Sgibbs		 && (out_msg.msg_req == MSG_EXT_SDTR)) {
103718781Sgibbs
103839217Sgibbs			/* Revert to Async */
103939217Sgibbs			adv_set_syncrate(adv, /*struct cam_path */NULL,
104039217Sgibbs					 tid_no, /*period*/0, /*offset*/0,
104139217Sgibbs					 ADV_TRANS_GOAL|ADV_TRANS_ACTIVE);
104218781Sgibbs		}
104318781Sgibbs		q_cntl &= ~QC_MSG_OUT;
104418781Sgibbs		adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl);
104518781Sgibbs	} else if (int_halt_code == ADV_HALT_SS_QUEUE_FULL) {
104639217Sgibbs		u_int8_t scsi_status;
104739217Sgibbs		union ccb *ccb;
104855945Sgibbs		u_int32_t cinfo_index;
104939217Sgibbs
105039217Sgibbs		scsi_status = adv_read_lram_8(adv, halt_q_addr
105139217Sgibbs					      + ADV_SCSIQ_SCSI_STATUS);
105255945Sgibbs		cinfo_index =
105355945Sgibbs		    adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX);
105455945Sgibbs		ccb = adv->ccb_infos[cinfo_index].ccb;
105539217Sgibbs		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
105640733Sgibbs		ccb->ccb_h.status |= CAM_DEV_QFRZN|CAM_SCSI_STATUS_ERROR;
105740733Sgibbs		ccb->csio.scsi_status = SCSI_STATUS_QUEUE_FULL;
105839217Sgibbs		adv_abort_ccb(adv, tid_no, ADV_TIX_TO_LUN(target_ix),
105939217Sgibbs			      /*ccb*/NULL, CAM_REQUEUE_REQ,
106039217Sgibbs			      /*queued_only*/TRUE);
106139217Sgibbs		scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B);
106239217Sgibbs		scsi_busy &= ~target_mask;
106339217Sgibbs		adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy);
106455945Sgibbs	} else {
106555945Sgibbs		printf("Unhandled Halt Code %x\n", int_halt_code);
106639217Sgibbs	}
106739217Sgibbs	adv_write_lram_16(adv, ADVV_HALTCODE_W, 0);
106839217Sgibbs}
106918781Sgibbs
107039217Sgibbsvoid
107139217Sgibbsadv_sdtr_to_period_offset(struct adv_softc *adv,
107239217Sgibbs			  u_int8_t sync_data, u_int8_t *period,
107339217Sgibbs			  u_int8_t *offset, int tid)
107439217Sgibbs{
107539217Sgibbs	if (adv->fix_asyn_xfer & ADV_TID_TO_TARGET_MASK(tid)
107639217Sgibbs	 && (sync_data == ASYN_SDTR_DATA_FIX_PCI_REV_AB)) {
107739217Sgibbs		*period = *offset = 0;
107839217Sgibbs	} else {
107939217Sgibbs		*period = adv->sdtr_period_tbl[((sync_data >> 4) & 0xF)];
108039217Sgibbs		*offset = sync_data & 0xF;
108139217Sgibbs	}
108239217Sgibbs}
108339217Sgibbs
108439217Sgibbsvoid
108539217Sgibbsadv_set_syncrate(struct adv_softc *adv, struct cam_path *path,
108639217Sgibbs		 u_int tid, u_int period, u_int offset, u_int type)
108739217Sgibbs{
108839217Sgibbs	struct adv_target_transinfo* tinfo;
108939217Sgibbs	u_int old_period;
109039217Sgibbs	u_int old_offset;
109139217Sgibbs	u_int8_t sdtr_data;
109239217Sgibbs
109339217Sgibbs	tinfo = &adv->tinfo[tid];
109439217Sgibbs
109539217Sgibbs	/* Filter our input */
109639217Sgibbs	sdtr_data = adv_period_offset_to_sdtr(adv, &period,
109739217Sgibbs					      &offset, tid);
109839217Sgibbs
109939217Sgibbs	old_period = tinfo->current.period;
110039217Sgibbs	old_offset = tinfo->current.offset;
110139217Sgibbs
110239217Sgibbs	if ((type & ADV_TRANS_CUR) != 0
110339217Sgibbs	 && ((old_period != period || old_offset != offset)
110439217Sgibbs	  || period == 0 || offset == 0) /*Changes in asyn fix settings*/) {
110539217Sgibbs		int s;
110639217Sgibbs		int halted;
110739217Sgibbs
110839217Sgibbs		s = splcam();
110939217Sgibbs		halted = adv_is_chip_halted(adv);
111039217Sgibbs		if (halted == 0)
111139217Sgibbs			/* Must halt the chip first */
111239217Sgibbs			adv_host_req_chip_halt(adv);
111339217Sgibbs
111439217Sgibbs		/* Update current hardware settings */
111539217Sgibbs		adv_set_sdtr_reg_at_id(adv, tid, sdtr_data);
111639217Sgibbs
111718781Sgibbs		/*
111839217Sgibbs		 * If a target can run in sync mode, we don't need
111939217Sgibbs		 * to check it for sync problems.
112018781Sgibbs		 */
112139217Sgibbs		if (offset != 0)
112239217Sgibbs			adv->fix_asyn_xfer &= ~ADV_TID_TO_TARGET_MASK(tid);
112318781Sgibbs
112439217Sgibbs		if (halted == 0)
112539217Sgibbs			/* Start the chip again */
112639217Sgibbs			adv_start_chip(adv);
112718781Sgibbs
112839217Sgibbs		splx(s);
112939217Sgibbs		tinfo->current.period = period;
113039217Sgibbs		tinfo->current.offset = offset;
113139217Sgibbs
113239217Sgibbs		if (path != NULL) {
113339217Sgibbs			/*
113439217Sgibbs			 * Tell the SCSI layer about the
113539217Sgibbs			 * new transfer parameters.
113639217Sgibbs			 */
113739217Sgibbs			struct	ccb_trans_settings neg;
113839217Sgibbs
113939217Sgibbs			neg.sync_period = period;
114039217Sgibbs			neg.sync_offset = offset;
114139217Sgibbs			neg.valid = CCB_TRANS_SYNC_RATE_VALID
114239217Sgibbs				  | CCB_TRANS_SYNC_OFFSET_VALID;
114339217Sgibbs			xpt_setup_ccb(&neg.ccb_h, path, /*priority*/1);
114439217Sgibbs			xpt_async(AC_TRANSFER_NEG, path, &neg);
114539217Sgibbs		}
114639217Sgibbs	}
114739217Sgibbs
114839217Sgibbs	if ((type & ADV_TRANS_GOAL) != 0) {
114939217Sgibbs		tinfo->goal.period = period;
115039217Sgibbs		tinfo->goal.offset = offset;
115139217Sgibbs	}
115239217Sgibbs
115339217Sgibbs	if ((type & ADV_TRANS_USER) != 0) {
115439217Sgibbs		tinfo->user.period = period;
115539217Sgibbs		tinfo->user.offset = offset;
115639217Sgibbs	}
115739217Sgibbs}
115839217Sgibbs
115939217Sgibbsu_int8_t
116039217Sgibbsadv_period_offset_to_sdtr(struct adv_softc *adv, u_int *period,
116139217Sgibbs			  u_int *offset, int tid)
116239217Sgibbs{
116339217Sgibbs	u_int i;
116439217Sgibbs	u_int dummy_offset;
116539217Sgibbs	u_int dummy_period;
116639217Sgibbs
116739217Sgibbs	if (offset == NULL) {
116839217Sgibbs		dummy_offset = 0;
116939217Sgibbs		offset = &dummy_offset;
117039217Sgibbs	}
117139217Sgibbs
117239217Sgibbs	if (period == NULL) {
117339217Sgibbs		dummy_period = 0;
117439217Sgibbs		period = &dummy_period;
117539217Sgibbs	}
117639217Sgibbs
117739217Sgibbs	*offset = MIN(ADV_SYN_MAX_OFFSET, *offset);
117839217Sgibbs	if (*period != 0 && *offset != 0) {
117939217Sgibbs		for (i = 0; i < adv->sdtr_period_tbl_size; i++) {
118039217Sgibbs			if (*period <= adv->sdtr_period_tbl[i]) {
118139217Sgibbs				/*
118239217Sgibbs				 * When responding to a target that requests
118339217Sgibbs				 * sync, the requested  rate may fall between
118439217Sgibbs				 * two rates that we can output, but still be
118539217Sgibbs				 * a rate that we can receive.  Because of this,
118639217Sgibbs				 * we want to respond to the target with
118739217Sgibbs				 * the same rate that it sent to us even
118839217Sgibbs				 * if the period we use to send data to it
118939217Sgibbs				 * is lower.  Only lower the response period
119039217Sgibbs				 * if we must.
119139217Sgibbs				 */
119239217Sgibbs				if (i == 0 /* Our maximum rate */)
119339217Sgibbs					*period = adv->sdtr_period_tbl[0];
119439217Sgibbs				return ((i << 4) | *offset);
119518781Sgibbs			}
119618781Sgibbs		}
119718781Sgibbs	}
119839217Sgibbs
119939217Sgibbs	/* Must go async */
120039217Sgibbs	*period = 0;
120139217Sgibbs	*offset = 0;
120239217Sgibbs	if (adv->fix_asyn_xfer & ADV_TID_TO_TARGET_MASK(tid))
120339217Sgibbs		return (ASYN_SDTR_DATA_FIX_PCI_REV_AB);
120439217Sgibbs	return (0);
120518781Sgibbs}
120618781Sgibbs
120718781Sgibbs/* Internal Routines */
120818781Sgibbs
120918781Sgibbsstatic void
121039217Sgibbsadv_read_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr,
121139217Sgibbs		       u_int16_t *buffer, int count)
121218781Sgibbs{
121318781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
121418781Sgibbs	ADV_INSW(adv, ADV_LRAM_DATA, buffer, count);
121518781Sgibbs}
121618781Sgibbs
121718781Sgibbsstatic void
121839217Sgibbsadv_write_lram_16_multi(struct adv_softc *adv, u_int16_t s_addr,
121939217Sgibbs			u_int16_t *buffer, int count)
122018781Sgibbs{
122118781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
122218781Sgibbs	ADV_OUTSW(adv, ADV_LRAM_DATA, buffer, count);
122318781Sgibbs}
122418781Sgibbs
122518781Sgibbsstatic void
122639217Sgibbsadv_mset_lram_16(struct adv_softc *adv, u_int16_t s_addr,
122739217Sgibbs		 u_int16_t set_value, int count)
122818781Sgibbs{
122918781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
123039217Sgibbs	bus_space_set_multi_2(adv->tag, adv->bsh, ADV_LRAM_DATA,
123139217Sgibbs			      set_value, count);
123218781Sgibbs}
123318781Sgibbs
123418781Sgibbsstatic u_int32_t
123539217Sgibbsadv_msum_lram_16(struct adv_softc *adv, u_int16_t s_addr, int count)
123618781Sgibbs{
123718781Sgibbs	u_int32_t	sum;
123818781Sgibbs	int		i;
123918781Sgibbs
124018781Sgibbs	sum = 0;
124139217Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
124239217Sgibbs	for (i = 0; i < count; i++)
124339217Sgibbs		sum += ADV_INW(adv, ADV_LRAM_DATA);
124418781Sgibbs	return (sum);
124518781Sgibbs}
124618781Sgibbs
124718781Sgibbsstatic int
124839217Sgibbsadv_write_and_verify_lram_16(struct adv_softc *adv, u_int16_t addr,
124939217Sgibbs			     u_int16_t value)
125018781Sgibbs{
125118781Sgibbs	int	retval;
125218781Sgibbs
125318781Sgibbs	retval = 0;
125418781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
125518781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, value);
125639217Sgibbs	DELAY(10000);
125718781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
125818781Sgibbs	if (value != ADV_INW(adv, ADV_LRAM_DATA))
125918781Sgibbs		retval = 1;
126018781Sgibbs	return (retval);
126118781Sgibbs}
126218781Sgibbs
126318781Sgibbsstatic u_int32_t
126439217Sgibbsadv_read_lram_32(struct adv_softc *adv, u_int16_t addr)
126518781Sgibbs{
126618781Sgibbs	u_int16_t           val_low, val_high;
126718781Sgibbs
126818781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
126918781Sgibbs
127018781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
127118781Sgibbs	val_high = ADV_INW(adv, ADV_LRAM_DATA);
127218781Sgibbs	val_low = ADV_INW(adv, ADV_LRAM_DATA);
127318781Sgibbs#else
127418781Sgibbs	val_low = ADV_INW(adv, ADV_LRAM_DATA);
127518781Sgibbs	val_high = ADV_INW(adv, ADV_LRAM_DATA);
127618781Sgibbs#endif
127718781Sgibbs
127818781Sgibbs	return (((u_int32_t)val_high << 16) | (u_int32_t)val_low);
127918781Sgibbs}
128018781Sgibbs
128118781Sgibbsstatic void
128239217Sgibbsadv_write_lram_32(struct adv_softc *adv, u_int16_t addr, u_int32_t value)
128318781Sgibbs{
128418781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, addr);
128518781Sgibbs
128618781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
128718781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)((value >> 16) & 0xFFFF));
128818781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)(value & 0xFFFF));
128918781Sgibbs#else
129018781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)(value & 0xFFFF));
129118781Sgibbs	ADV_OUTW(adv, ADV_LRAM_DATA, (u_int16_t)((value >> 16) & 0xFFFF));
129218781Sgibbs#endif
129318781Sgibbs}
129418781Sgibbs
129518781Sgibbsstatic void
129639217Sgibbsadv_write_lram_32_multi(struct adv_softc *adv, u_int16_t s_addr,
129739217Sgibbs			u_int32_t *buffer, int count)
129818781Sgibbs{
129918781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
130039217Sgibbs	ADV_OUTSW(adv, ADV_LRAM_DATA, (u_int16_t *)buffer, count * 2);
130118781Sgibbs}
130218781Sgibbs
130318781Sgibbsstatic u_int16_t
130439217Sgibbsadv_read_eeprom_16(struct adv_softc *adv, u_int8_t addr)
130518781Sgibbs{
130618781Sgibbs	u_int16_t read_wval;
130718781Sgibbs	u_int8_t  cmd_reg;
130818781Sgibbs
130918781Sgibbs	adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_DISABLE);
131018781Sgibbs	DELAY(1000);
131118781Sgibbs	cmd_reg = addr | ADV_EEPROM_CMD_READ;
131218781Sgibbs	adv_write_eeprom_cmd_reg(adv, cmd_reg);
131318781Sgibbs	DELAY(1000);
131418781Sgibbs	read_wval = ADV_INW(adv, ADV_EEPROM_DATA);
131518781Sgibbs	DELAY(1000);
131618781Sgibbs	return (read_wval);
131718781Sgibbs}
131818781Sgibbs
131918781Sgibbsstatic u_int16_t
132039217Sgibbsadv_write_eeprom_16(struct adv_softc *adv, u_int8_t addr, u_int16_t value)
132118781Sgibbs{
132218781Sgibbs	u_int16_t	read_value;
132318781Sgibbs
132418781Sgibbs	read_value = adv_read_eeprom_16(adv, addr);
132518781Sgibbs	if (read_value != value) {
132618781Sgibbs		adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_ENABLE);
132718781Sgibbs		DELAY(1000);
132818781Sgibbs
132918781Sgibbs		ADV_OUTW(adv, ADV_EEPROM_DATA, value);
133018781Sgibbs		DELAY(1000);
133118781Sgibbs
133218781Sgibbs		adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE | addr);
133318781Sgibbs		DELAY(20 * 1000);
133418781Sgibbs
133518781Sgibbs		adv_write_eeprom_cmd_reg(adv, ADV_EEPROM_CMD_WRITE_DISABLE);
133618781Sgibbs		DELAY(1000);
133718781Sgibbs		read_value = adv_read_eeprom_16(adv, addr);
133818781Sgibbs	}
133918781Sgibbs	return (read_value);
134018781Sgibbs}
134118781Sgibbs
134218781Sgibbsstatic int
134339217Sgibbsadv_write_eeprom_cmd_reg(struct adv_softc *adv, u_int8_t cmd_reg)
134418781Sgibbs{
134518781Sgibbs	u_int8_t read_back;
134618781Sgibbs	int	 retry;
134718781Sgibbs
134818781Sgibbs	retry = 0;
134918781Sgibbs	while (1) {
135018781Sgibbs		ADV_OUTB(adv, ADV_EEPROM_CMD, cmd_reg);
135118781Sgibbs		DELAY(1000);
135218781Sgibbs		read_back = ADV_INB(adv, ADV_EEPROM_CMD);
135318781Sgibbs		if (read_back == cmd_reg) {
135418781Sgibbs			return (1);
135518781Sgibbs		}
135618781Sgibbs		if (retry++ > ADV_EEPROM_MAX_RETRY) {
135718781Sgibbs			return (0);
135818781Sgibbs		}
135918781Sgibbs	}
136018781Sgibbs}
136118781Sgibbs
136218781Sgibbsstatic int
136339217Sgibbsadv_set_eeprom_config_once(struct adv_softc *adv,
136439217Sgibbs			   struct adv_eeprom_config *eeprom_config)
136518781Sgibbs{
136618781Sgibbs	int		n_error;
136718781Sgibbs	u_int16_t	*wbuf;
136818781Sgibbs	u_int16_t	sum;
136918781Sgibbs	u_int8_t	s_addr;
137018781Sgibbs	u_int8_t	cfg_beg;
137118781Sgibbs	u_int8_t	cfg_end;
137218781Sgibbs
137318781Sgibbs	wbuf = (u_int16_t *)eeprom_config;
137418781Sgibbs	n_error = 0;
137518781Sgibbs	sum = 0;
137618781Sgibbs	for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
137718781Sgibbs		sum += *wbuf;
137818781Sgibbs		if (*wbuf != adv_write_eeprom_16(adv, s_addr, *wbuf)) {
137918781Sgibbs			n_error++;
138018781Sgibbs		}
138118781Sgibbs	}
138218781Sgibbs	if (adv->type & ADV_VL) {
138318781Sgibbs		cfg_beg = ADV_EEPROM_CFG_BEG_VL;
138418781Sgibbs		cfg_end = ADV_EEPROM_MAX_ADDR_VL;
138518781Sgibbs	} else {
138618781Sgibbs		cfg_beg = ADV_EEPROM_CFG_BEG;
138718781Sgibbs		cfg_end = ADV_EEPROM_MAX_ADDR;
138818781Sgibbs	}
138918781Sgibbs
139018781Sgibbs	for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
139118781Sgibbs		sum += *wbuf;
139218781Sgibbs		if (*wbuf != adv_write_eeprom_16(adv, s_addr, *wbuf)) {
139318781Sgibbs			n_error++;
139418781Sgibbs		}
139518781Sgibbs	}
139618781Sgibbs	*wbuf = sum;
139718781Sgibbs	if (sum != adv_write_eeprom_16(adv, s_addr, sum)) {
139818781Sgibbs		n_error++;
139918781Sgibbs	}
140018781Sgibbs	wbuf = (u_int16_t *)eeprom_config;
140118781Sgibbs	for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
140218781Sgibbs		if (*wbuf != adv_read_eeprom_16(adv, s_addr)) {
140318781Sgibbs			n_error++;
140418781Sgibbs		}
140518781Sgibbs	}
140618781Sgibbs	for (s_addr = cfg_beg; s_addr <= cfg_end; s_addr++, wbuf++) {
140718781Sgibbs		if (*wbuf != adv_read_eeprom_16(adv, s_addr)) {
140818781Sgibbs			n_error++;
140918781Sgibbs		}
141018781Sgibbs	}
141118781Sgibbs	return (n_error);
141218781Sgibbs}
141318781Sgibbs
141418781Sgibbsstatic u_int32_t
141539217Sgibbsadv_load_microcode(struct adv_softc *adv, u_int16_t s_addr,
141639217Sgibbs		   u_int16_t *mcode_buf, u_int16_t mcode_size)
141718781Sgibbs{
141839217Sgibbs	u_int32_t chksum;
141939217Sgibbs	u_int16_t mcode_lram_size;
142039217Sgibbs	u_int16_t mcode_chksum;
142118781Sgibbs
142218781Sgibbs	mcode_lram_size = mcode_size >> 1;
142318781Sgibbs	/* XXX Why zero the memory just before you write the whole thing?? */
142439217Sgibbs	adv_mset_lram_16(adv, s_addr, 0, mcode_lram_size);
142518781Sgibbs	adv_write_lram_16_multi(adv, s_addr, mcode_buf, mcode_lram_size);
142618781Sgibbs
142718781Sgibbs	chksum = adv_msum_lram_16(adv, s_addr, mcode_lram_size);
142818781Sgibbs	mcode_chksum = (u_int16_t)adv_msum_lram_16(adv, ADV_CODE_SEC_BEG,
142939217Sgibbs						   ((mcode_size - s_addr
143039217Sgibbs						     - ADV_CODE_SEC_BEG) >> 1));
143118781Sgibbs	adv_write_lram_16(adv, ADVV_MCODE_CHKSUM_W, mcode_chksum);
143218781Sgibbs	adv_write_lram_16(adv, ADVV_MCODE_SIZE_W, mcode_size);
143318781Sgibbs	return (chksum);
143418781Sgibbs}
143518781Sgibbs
143618781Sgibbsstatic void
143739217Sgibbsadv_reinit_lram(struct adv_softc *adv) {
143839217Sgibbs	adv_init_lram(adv);
143939217Sgibbs	adv_init_qlink_var(adv);
144039217Sgibbs}
144139217Sgibbs
144239217Sgibbsstatic void
144339217Sgibbsadv_init_lram(struct adv_softc *adv)
144418781Sgibbs{
144539217Sgibbs	u_int8_t  i;
144639217Sgibbs	u_int16_t s_addr;
144718781Sgibbs
144818781Sgibbs	adv_mset_lram_16(adv, ADV_QADR_BEG, 0,
144939217Sgibbs			 (((adv->max_openings + 2 + 1) * 64) >> 1));
145018781Sgibbs
145118781Sgibbs	i = ADV_MIN_ACTIVE_QNO;
145218781Sgibbs	s_addr = ADV_QADR_BEG + ADV_QBLK_SIZE;
145318781Sgibbs
145418781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD,	i + 1);
145518781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, adv->max_openings);
145618781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i);
145718781Sgibbs	i++;
145818781Sgibbs	s_addr += ADV_QBLK_SIZE;
145918781Sgibbs	for (; i < adv->max_openings; i++, s_addr += ADV_QBLK_SIZE) {
146018781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i + 1);
146118781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, i - 1);
146218781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i);
146318781Sgibbs	}
146418781Sgibbs
146518781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, ADV_QLINK_END);
146618781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, adv->max_openings - 1);
146718781Sgibbs	adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, adv->max_openings);
146818781Sgibbs	i++;
146918781Sgibbs	s_addr += ADV_QBLK_SIZE;
147018781Sgibbs
147118781Sgibbs	for (; i <= adv->max_openings + 3; i++, s_addr += ADV_QBLK_SIZE) {
147218781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_FWD, i);
147318781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_BWD, i);
147418781Sgibbs		adv_write_lram_8(adv, s_addr + ADV_SCSIQ_B_QNO, i);
147518781Sgibbs	}
147618781Sgibbs}
147718781Sgibbs
147818781Sgibbsstatic int
147939217Sgibbsadv_init_microcode_var(struct adv_softc *adv)
148018781Sgibbs{
148139217Sgibbs	int	 i;
148218781Sgibbs
148318781Sgibbs	for (i = 0; i <= ADV_MAX_TID; i++) {
148439217Sgibbs
148539217Sgibbs		/* Start out async all around */
148639217Sgibbs		adv_set_syncrate(adv, /*path*/NULL,
148739217Sgibbs				 i, 0, 0,
148839217Sgibbs				 ADV_TRANS_GOAL|ADV_TRANS_CUR);
148918781Sgibbs	}
149018781Sgibbs
149118781Sgibbs	adv_init_qlink_var(adv);
149218781Sgibbs
149318781Sgibbs	adv_write_lram_8(adv, ADVV_DISC_ENABLE_B, adv->disc_enable);
149418781Sgibbs	adv_write_lram_8(adv, ADVV_HOSTSCSI_ID_B, 0x01 << adv->scsi_id);
149518781Sgibbs
149639217Sgibbs	adv_write_lram_32(adv, ADVV_OVERRUN_PADDR_D, adv->overrun_physbase);
149718781Sgibbs
149839217Sgibbs	adv_write_lram_32(adv, ADVV_OVERRUN_BSIZE_D, ADV_OVERRUN_BSIZE);
149918781Sgibbs
150018781Sgibbs	ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR);
150118781Sgibbs	if (ADV_INW(adv, ADV_REG_PROG_COUNTER) != ADV_MCODE_START_ADDR) {
150239217Sgibbs		printf("adv%d: Unable to set program counter. Aborting.\n",
150318781Sgibbs		       adv->unit);
150418781Sgibbs		return (1);
150518781Sgibbs	}
150618781Sgibbs	return (0);
150718781Sgibbs}
150818781Sgibbs
150918781Sgibbsstatic void
151039217Sgibbsadv_init_qlink_var(struct adv_softc *adv)
151118781Sgibbs{
151218781Sgibbs	int	  i;
151318781Sgibbs	u_int16_t lram_addr;
151418781Sgibbs
151518781Sgibbs	adv_write_lram_8(adv, ADVV_NEXTRDY_B, 1);
151618781Sgibbs	adv_write_lram_8(adv, ADVV_DONENEXT_B, adv->max_openings);
151718781Sgibbs
151818781Sgibbs	adv_write_lram_16(adv, ADVV_FREE_Q_HEAD_W, 1);
151918781Sgibbs	adv_write_lram_16(adv, ADVV_DONE_Q_TAIL_W, adv->max_openings);
152018781Sgibbs
152118781Sgibbs	adv_write_lram_8(adv, ADVV_BUSY_QHEAD_B,
152218781Sgibbs			 (u_int8_t)((int) adv->max_openings + 1));
152318781Sgibbs	adv_write_lram_8(adv, ADVV_DISC1_QHEAD_B,
152418781Sgibbs			 (u_int8_t)((int) adv->max_openings + 2));
152518781Sgibbs
152618781Sgibbs	adv_write_lram_8(adv, ADVV_TOTAL_READY_Q_B, adv->max_openings);
152718781Sgibbs
152818781Sgibbs	adv_write_lram_16(adv, ADVV_ASCDVC_ERR_CODE_W, 0);
152918781Sgibbs	adv_write_lram_16(adv, ADVV_HALTCODE_W, 0);
153018781Sgibbs	adv_write_lram_8(adv, ADVV_STOP_CODE_B, 0);
153118781Sgibbs	adv_write_lram_8(adv, ADVV_SCSIBUSY_B, 0);
153218781Sgibbs	adv_write_lram_8(adv, ADVV_WTM_FLAG_B, 0);
153339217Sgibbs	adv_write_lram_8(adv, ADVV_Q_DONE_IN_PROGRESS_B, 0);
153418781Sgibbs
153518781Sgibbs	lram_addr = ADV_QADR_BEG;
153618781Sgibbs	for (i = 0; i < 32; i++, lram_addr += 2)
153718781Sgibbs		adv_write_lram_16(adv, lram_addr, 0);
153818781Sgibbs}
153939217Sgibbs
154018781Sgibbsstatic void
154139217Sgibbsadv_disable_interrupt(struct adv_softc *adv)
154218781Sgibbs{
154318781Sgibbs	u_int16_t cfg;
154418781Sgibbs
154518781Sgibbs	cfg = ADV_INW(adv, ADV_CONFIG_LSW);
154618781Sgibbs	ADV_OUTW(adv, ADV_CONFIG_LSW, cfg & ~ADV_CFG_LSW_HOST_INT_ON);
154718781Sgibbs}
154818781Sgibbs
154918781Sgibbsstatic void
155039217Sgibbsadv_enable_interrupt(struct adv_softc *adv)
155118781Sgibbs{
155218781Sgibbs	u_int16_t cfg;
155318781Sgibbs
155418781Sgibbs	cfg = ADV_INW(adv, ADV_CONFIG_LSW);
155518781Sgibbs	ADV_OUTW(adv, ADV_CONFIG_LSW, cfg | ADV_CFG_LSW_HOST_INT_ON);
155618781Sgibbs}
155718781Sgibbs
155818781Sgibbsstatic void
155939217Sgibbsadv_toggle_irq_act(struct adv_softc *adv)
156018781Sgibbs{
156118781Sgibbs	ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_IRQ_ACT);
156218781Sgibbs	ADV_OUTW(adv, ADV_CHIP_STATUS, 0);
156318781Sgibbs}
156418781Sgibbs
156539217Sgibbsvoid
156639217Sgibbsadv_start_execution(struct adv_softc *adv)
156718781Sgibbs{
156818781Sgibbs	if (adv_read_lram_8(adv, ADV_STOP_CODE_B) != 0) {
156918781Sgibbs		adv_write_lram_8(adv, ADV_STOP_CODE_B, 0);
157018781Sgibbs	}
157118781Sgibbs}
157218781Sgibbs
157355945Sgibbsint
157439217Sgibbsadv_stop_chip(struct adv_softc *adv)
157518781Sgibbs{
157618781Sgibbs	u_int8_t cc_val;
157718781Sgibbs
157818781Sgibbs	cc_val = ADV_INB(adv, ADV_CHIP_CTRL)
157918781Sgibbs		 & (~(ADV_CC_SINGLE_STEP | ADV_CC_TEST | ADV_CC_DIAG));
158018781Sgibbs	ADV_OUTB(adv, ADV_CHIP_CTRL, cc_val | ADV_CC_HALT);
158118781Sgibbs	adv_set_chip_ih(adv, ADV_INS_HALT);
158218781Sgibbs	adv_set_chip_ih(adv, ADV_INS_RFLAG_WTM);
158318781Sgibbs	if ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_HALTED) == 0) {
158418781Sgibbs		return (0);
158518781Sgibbs	}
158618781Sgibbs	return (1);
158718781Sgibbs}
158818781Sgibbs
158939217Sgibbsstatic int
159039217Sgibbsadv_host_req_chip_halt(struct adv_softc *adv)
159139217Sgibbs{
159239217Sgibbs	int	 count;
159339217Sgibbs	u_int8_t saved_stop_code;
159439217Sgibbs
159539217Sgibbs	if (adv_is_chip_halted(adv))
159639217Sgibbs		return (1);
159739217Sgibbs
159839217Sgibbs	count = 0;
159939217Sgibbs	saved_stop_code = adv_read_lram_8(adv, ADVV_STOP_CODE_B);
160039217Sgibbs	adv_write_lram_8(adv, ADVV_STOP_CODE_B,
160139217Sgibbs			 ADV_STOP_HOST_REQ_RISC_HALT | ADV_STOP_REQ_RISC_STOP);
160239217Sgibbs	while (adv_is_chip_halted(adv) == 0
160339217Sgibbs	    && count++ < 2000)
160439217Sgibbs		;
160539217Sgibbs
160639217Sgibbs	adv_write_lram_8(adv, ADVV_STOP_CODE_B, saved_stop_code);
160739217Sgibbs	return (count < 2000);
160839217Sgibbs}
160939217Sgibbs
161018781Sgibbsstatic void
161139217Sgibbsadv_set_chip_ih(struct adv_softc *adv, u_int16_t ins_code)
161218781Sgibbs{
161318781Sgibbs	adv_set_bank(adv, 1);
161418781Sgibbs	ADV_OUTW(adv, ADV_REG_IH, ins_code);
161518781Sgibbs	adv_set_bank(adv, 0);
161618781Sgibbs}
161718781Sgibbs
1618153072Sru#if 0
161918781Sgibbsstatic u_int8_t
162039217Sgibbsadv_get_chip_scsi_ctrl(struct adv_softc *adv)
162118781Sgibbs{
162218781Sgibbs	u_int8_t scsi_ctrl;
162318781Sgibbs
162418781Sgibbs	adv_set_bank(adv, 1);
162518781Sgibbs	scsi_ctrl = ADV_INB(adv, ADV_REG_SC);
162618781Sgibbs	adv_set_bank(adv, 0);
162718781Sgibbs	return (scsi_ctrl);
162818781Sgibbs}
162918781Sgibbs#endif
163018781Sgibbs
163118781Sgibbs/*
163218781Sgibbs * XXX Looks like more padding issues in this routine as well.
163318781Sgibbs *     There has to be a way to turn this into an insw.
163418781Sgibbs */
163518781Sgibbsstatic void
163639217Sgibbsadv_get_q_info(struct adv_softc *adv, u_int16_t s_addr,
163739217Sgibbs	       u_int16_t *inbuf, int words)
163818781Sgibbs{
163918781Sgibbs	int	i;
164018781Sgibbs
164118781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
164218781Sgibbs	for (i = 0; i < words; i++, inbuf++) {
164318781Sgibbs		if (i == 5) {
164418781Sgibbs			continue;
164518781Sgibbs		}
164618781Sgibbs		*inbuf = ADV_INW(adv, ADV_LRAM_DATA);
164718781Sgibbs	}
164818781Sgibbs}
164918781Sgibbs
165018781Sgibbsstatic u_int
165139217Sgibbsadv_get_num_free_queues(struct adv_softc *adv, u_int8_t n_qs)
165218781Sgibbs{
165318781Sgibbs	u_int	  cur_used_qs;
165418781Sgibbs	u_int	  cur_free_qs;
165518781Sgibbs
165639217Sgibbs	cur_used_qs = adv->cur_active + ADV_MIN_FREE_Q;
165718781Sgibbs
165818781Sgibbs	if ((cur_used_qs + n_qs) <= adv->max_openings) {
165918781Sgibbs		cur_free_qs = adv->max_openings - cur_used_qs;
166018781Sgibbs		return (cur_free_qs);
166118781Sgibbs	}
166239217Sgibbs	adv->openings_needed = n_qs;
166318781Sgibbs	return (0);
166418781Sgibbs}
166518781Sgibbs
166618781Sgibbsstatic u_int8_t
166739217Sgibbsadv_alloc_free_queues(struct adv_softc *adv, u_int8_t free_q_head,
166839217Sgibbs		      u_int8_t n_free_q)
166918781Sgibbs{
167018781Sgibbs	int i;
167118781Sgibbs
167218781Sgibbs	for (i = 0; i < n_free_q; i++) {
167318781Sgibbs		free_q_head = adv_alloc_free_queue(adv, free_q_head);
167418781Sgibbs		if (free_q_head == ADV_QLINK_END)
167518781Sgibbs			break;
167618781Sgibbs	}
167718781Sgibbs	return (free_q_head);
167818781Sgibbs}
167918781Sgibbs
168018781Sgibbsstatic u_int8_t
168139217Sgibbsadv_alloc_free_queue(struct adv_softc *adv, u_int8_t free_q_head)
168218781Sgibbs{
168318781Sgibbs	u_int16_t	q_addr;
168418781Sgibbs	u_int8_t	next_qp;
168518781Sgibbs	u_int8_t	q_status;
168618781Sgibbs
168718781Sgibbs	next_qp = ADV_QLINK_END;
168818781Sgibbs	q_addr = ADV_QNO_TO_QADDR(free_q_head);
168918781Sgibbs	q_status = adv_read_lram_8(adv,	q_addr + ADV_SCSIQ_B_STATUS);
169018781Sgibbs
169118781Sgibbs	if ((q_status & QS_READY) == 0)
169218781Sgibbs		next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD);
169318781Sgibbs
169418781Sgibbs	return (next_qp);
169518781Sgibbs}
169618781Sgibbs
169718781Sgibbsstatic int
169839217Sgibbsadv_send_scsi_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq,
169939217Sgibbs		    u_int8_t n_q_required)
170018781Sgibbs{
170118781Sgibbs	u_int8_t	free_q_head;
170218781Sgibbs	u_int8_t	next_qp;
170318781Sgibbs	u_int8_t	tid_no;
170418781Sgibbs	u_int8_t	target_ix;
170518781Sgibbs	int		retval;
170618781Sgibbs
170718781Sgibbs	retval = 1;
170818781Sgibbs	target_ix = scsiq->q2.target_ix;
170918781Sgibbs	tid_no = ADV_TIX_TO_TID(target_ix);
171018781Sgibbs	free_q_head = adv_read_lram_16(adv, ADVV_FREE_Q_HEAD_W) & 0xFF;
171118781Sgibbs	if ((next_qp = adv_alloc_free_queues(adv, free_q_head, n_q_required))
171218781Sgibbs	    != ADV_QLINK_END) {
171318781Sgibbs		scsiq->q1.q_no = free_q_head;
171418781Sgibbs
171518781Sgibbs		/*
171618781Sgibbs		 * Now that we know our Q number, point our sense
171739217Sgibbs		 * buffer pointer to a bus dma mapped area where
171839217Sgibbs		 * we can dma the data to.
171918781Sgibbs		 */
172039217Sgibbs		scsiq->q1.sense_addr = adv->sense_physbase
172139217Sgibbs		    + ((free_q_head - 1) * sizeof(struct scsi_sense_data));
172218781Sgibbs		adv_put_ready_sg_list_queue(adv, scsiq, free_q_head);
172318781Sgibbs		adv_write_lram_16(adv, ADVV_FREE_Q_HEAD_W, next_qp);
172418781Sgibbs		adv->cur_active += n_q_required;
172518781Sgibbs		retval = 0;
172618781Sgibbs	}
172718781Sgibbs	return (retval);
172818781Sgibbs}
172918781Sgibbs
173018781Sgibbs
173118781Sgibbsstatic void
173239217Sgibbsadv_put_ready_sg_list_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq,
173339217Sgibbs			    u_int q_no)
173418781Sgibbs{
173518781Sgibbs	u_int8_t	sg_list_dwords;
173618781Sgibbs	u_int8_t	sg_index, i;
173718781Sgibbs	u_int8_t	sg_entry_cnt;
173818781Sgibbs	u_int8_t	next_qp;
173918781Sgibbs	u_int16_t	q_addr;
174018781Sgibbs	struct		adv_sg_head *sg_head;
174118781Sgibbs	struct		adv_sg_list_q scsi_sg_q;
174218781Sgibbs
174318781Sgibbs	sg_head = scsiq->sg_head;
174418781Sgibbs
174518781Sgibbs	if (sg_head) {
174618781Sgibbs		sg_entry_cnt = sg_head->entry_cnt - 1;
174718781Sgibbs#ifdef DIAGNOSTIC
174818781Sgibbs		if (sg_entry_cnt == 0)
174939217Sgibbs			panic("adv_put_ready_sg_list_queue: ScsiQ with "
175039217Sgibbs			      "a SG list but only one element");
175118781Sgibbs		if ((scsiq->q1.cntl & QC_SG_HEAD) == 0)
175239217Sgibbs			panic("adv_put_ready_sg_list_queue: ScsiQ with "
175339217Sgibbs			      "a SG list but QC_SG_HEAD not set");
175418781Sgibbs#endif
175518781Sgibbs		q_addr = ADV_QNO_TO_QADDR(q_no);
175618781Sgibbs		sg_index = 1;
175718781Sgibbs		scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
175818781Sgibbs		scsi_sg_q.sg_head_qp = q_no;
175918781Sgibbs		scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
176018781Sgibbs		for (i = 0; i < sg_head->queue_cnt; i++) {
176118781Sgibbs			u_int8_t segs_this_q;
176218781Sgibbs
176318781Sgibbs			if (sg_entry_cnt > ADV_SG_LIST_PER_Q)
176418781Sgibbs				segs_this_q = ADV_SG_LIST_PER_Q;
176518781Sgibbs			else {
176618781Sgibbs				/* This will be the last segment then */
176718781Sgibbs				segs_this_q = sg_entry_cnt;
176818781Sgibbs				scsi_sg_q.cntl |= QCSG_SG_XFER_END;
176918781Sgibbs			}
177018781Sgibbs			scsi_sg_q.seq_no = i + 1;
177139217Sgibbs			sg_list_dwords = segs_this_q << 1;
177218781Sgibbs			if (i == 0) {
177318781Sgibbs				scsi_sg_q.sg_list_cnt = segs_this_q;
177418781Sgibbs				scsi_sg_q.sg_cur_list_cnt = segs_this_q;
177518781Sgibbs			} else {
177618781Sgibbs				scsi_sg_q.sg_list_cnt = segs_this_q - 1;
177718781Sgibbs				scsi_sg_q.sg_cur_list_cnt = segs_this_q - 1;
177818781Sgibbs			}
177918781Sgibbs			next_qp = adv_read_lram_8(adv, q_addr + ADV_SCSIQ_B_FWD);
178018781Sgibbs			scsi_sg_q.q_no = next_qp;
178118781Sgibbs			q_addr = ADV_QNO_TO_QADDR(next_qp);
178218781Sgibbs
178339217Sgibbs			adv_write_lram_16_multi(adv,
178439217Sgibbs						q_addr + ADV_SCSIQ_SGHD_CPY_BEG,
178518781Sgibbs						(u_int16_t *)&scsi_sg_q,
178618781Sgibbs						sizeof(scsi_sg_q) >> 1);
178718781Sgibbs			adv_write_lram_32_multi(adv, q_addr + ADV_SGQ_LIST_BEG,
178818781Sgibbs						(u_int32_t *)&sg_head->sg_list[sg_index],
178918781Sgibbs						sg_list_dwords);
179018781Sgibbs			sg_entry_cnt -= segs_this_q;
179118781Sgibbs			sg_index += ADV_SG_LIST_PER_Q;
179218781Sgibbs		}
179318781Sgibbs	}
179418781Sgibbs	adv_put_ready_queue(adv, scsiq, q_no);
179518781Sgibbs}
179618781Sgibbs
179718781Sgibbsstatic void
179839217Sgibbsadv_put_ready_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq,
179939217Sgibbs		    u_int q_no)
180018781Sgibbs{
180139217Sgibbs	struct		adv_target_transinfo* tinfo;
180239217Sgibbs	u_int		q_addr;
180339217Sgibbs	u_int		tid_no;
180418781Sgibbs
180539217Sgibbs	tid_no = ADV_TIX_TO_TID(scsiq->q2.target_ix);
180639217Sgibbs	tinfo = &adv->tinfo[tid_no];
180746581Sken	if ((tinfo->current.period != tinfo->goal.period)
180846581Sken	 || (tinfo->current.offset != tinfo->goal.offset)) {
180918781Sgibbs
181039217Sgibbs		adv_msgout_sdtr(adv, tinfo->goal.period, tinfo->goal.offset);
181118781Sgibbs		scsiq->q1.cntl |= QC_MSG_OUT;
181218781Sgibbs	}
181318781Sgibbs	q_addr = ADV_QNO_TO_QADDR(q_no);
181418781Sgibbs
181518781Sgibbs	scsiq->q1.status = QS_FREE;
181618781Sgibbs
181718781Sgibbs	adv_write_lram_16_multi(adv, q_addr + ADV_SCSIQ_CDB_BEG,
181818781Sgibbs				(u_int16_t *)scsiq->cdbptr,
181918781Sgibbs				scsiq->q2.cdb_len >> 1);
182018781Sgibbs
182118781Sgibbs#if BYTE_ORDER == BIG_ENDIAN
182218781Sgibbs	adv_adj_scsiq_endian(scsiq);
182318781Sgibbs#endif
182418781Sgibbs
182518781Sgibbs	adv_put_scsiq(adv, q_addr + ADV_SCSIQ_CPY_BEG,
182618781Sgibbs		      (u_int16_t *) &scsiq->q1.cntl,
182718781Sgibbs		      ((sizeof(scsiq->q1) + sizeof(scsiq->q2)) / 2) - 1);
182818781Sgibbs
1829153072Sru#ifdef CC_WRITE_IO_COUNT
183018781Sgibbs	adv_write_lram_16(adv, q_addr + ADV_SCSIQ_W_REQ_COUNT,
183118781Sgibbs			  adv->req_count);
183218781Sgibbs#endif
183318781Sgibbs
1834153072Sru#ifdef CC_CLEAR_DMA_REMAIN
183518781Sgibbs
183618781Sgibbs	adv_write_lram_32(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_ADDR, 0);
183718781Sgibbs	adv_write_lram_32(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_CNT, 0);
183818781Sgibbs#endif
183918781Sgibbs
184018781Sgibbs	adv_write_lram_16(adv, q_addr + ADV_SCSIQ_B_STATUS,
184118781Sgibbs			  (scsiq->q1.q_no << 8) | QS_READY);
184218781Sgibbs}
184318781Sgibbs
184418781Sgibbsstatic void
184539217Sgibbsadv_put_scsiq(struct adv_softc *adv, u_int16_t s_addr,
184639217Sgibbs	      u_int16_t *buffer, int words)
184718781Sgibbs{
184818781Sgibbs	int	i;
184918781Sgibbs
185018781Sgibbs	/*
185118781Sgibbs	 * XXX This routine makes *gross* assumptions
185218781Sgibbs	 * about padding in the data structures.
185318781Sgibbs	 * Either the data structures should have explicit
185418781Sgibbs	 * padding members added, or they should have padding
185518781Sgibbs	 * turned off via compiler attributes depending on
185618781Sgibbs	 * which yields better overall performance.  My hunch
185718781Sgibbs	 * would be that turning off padding would be the
185818781Sgibbs	 * faster approach as an outsw is much faster than
185918781Sgibbs	 * this crude loop and accessing un-aligned data
186018781Sgibbs	 * members isn't *that* expensive.  The other choice
186118781Sgibbs	 * would be to modify the ASC script so that the
186218781Sgibbs	 * the adv_scsiq_1 structure can be re-arranged so
186318781Sgibbs	 * padding isn't required.
186418781Sgibbs	 */
186518781Sgibbs	ADV_OUTW(adv, ADV_LRAM_ADDR, s_addr);
186618781Sgibbs	for (i = 0; i < words; i++, buffer++) {
186718781Sgibbs		if (i == 2 || i == 10) {
186818781Sgibbs			continue;
186918781Sgibbs		}
187018781Sgibbs		ADV_OUTW(adv, ADV_LRAM_DATA, *buffer);
187118781Sgibbs	}
187218781Sgibbs}
187318781Sgibbs
1874111342Sobrien#if BYTE_ORDER == BIG_ENDIAN
1875111342Sobrienvoid
1876111342Sobrienadv_adj_endian_qdone_info(struct adv_q_done_info *scsiq)
1877111342Sobrien{
1878111342Sobrien
1879111342Sobrien	panic("adv(4) not supported on big-endian machines.\n");
1880111342Sobrien}
1881111342Sobrien
1882111342Sobrienvoid
1883111342Sobrienadv_adj_scsiq_endian(struct adv_scsi_q *scsiq)
1884111342Sobrien{
1885111342Sobrien
1886111342Sobrien	panic("adv(4) not supported on big-endian machines.\n");
1887111342Sobrien}
1888111342Sobrien#endif
1889111342Sobrien
189039217Sgibbsstatic void
189139217Sgibbsadv_handle_extmsg_in(struct adv_softc *adv, u_int16_t halt_q_addr,
189239217Sgibbs		     u_int8_t q_cntl, target_bit_vector target_mask,
189339217Sgibbs		     int tid_no)
189418781Sgibbs{
189539217Sgibbs	struct	ext_msg ext_msg;
189618781Sgibbs
189739217Sgibbs	adv_read_lram_16_multi(adv, ADVV_MSGIN_BEG, (u_int16_t *) &ext_msg,
189839217Sgibbs			       sizeof(ext_msg) >> 1);
189939217Sgibbs	if ((ext_msg.msg_type == MSG_EXTENDED)
190039217Sgibbs	 && (ext_msg.msg_req == MSG_EXT_SDTR)
190139217Sgibbs	 && (ext_msg.msg_len == MSG_EXT_SDTR_LEN)) {
190255945Sgibbs		union	  ccb *ccb;
190355945Sgibbs		struct	  adv_target_transinfo* tinfo;
190455945Sgibbs		u_int32_t cinfo_index;
190539217Sgibbs		u_int	 period;
190639217Sgibbs		u_int	 offset;
190739217Sgibbs		int	 sdtr_accept;
190839217Sgibbs		u_int8_t orig_offset;
190939217Sgibbs
191055945Sgibbs		cinfo_index =
191155945Sgibbs		    adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX);
191255945Sgibbs		ccb = adv->ccb_infos[cinfo_index].ccb;
191339217Sgibbs		tinfo = &adv->tinfo[tid_no];
191439217Sgibbs		sdtr_accept = TRUE;
191539217Sgibbs
191639217Sgibbs		orig_offset = ext_msg.req_ack_offset;
191739217Sgibbs		if (ext_msg.xfer_period < tinfo->goal.period) {
191839217Sgibbs                	sdtr_accept = FALSE;
191939217Sgibbs			ext_msg.xfer_period = tinfo->goal.period;
192039217Sgibbs		}
192139217Sgibbs
192239217Sgibbs		/* Perform range checking */
192339217Sgibbs		period = ext_msg.xfer_period;
192439217Sgibbs		offset = ext_msg.req_ack_offset;
192539217Sgibbs		adv_period_offset_to_sdtr(adv, &period,  &offset, tid_no);
192639217Sgibbs		ext_msg.xfer_period = period;
192739217Sgibbs		ext_msg.req_ack_offset = offset;
192839217Sgibbs
192939217Sgibbs		/* Record our current sync settings */
193039217Sgibbs		adv_set_syncrate(adv, ccb->ccb_h.path,
193139217Sgibbs				 tid_no, ext_msg.xfer_period,
193239217Sgibbs				 ext_msg.req_ack_offset,
193339217Sgibbs				 ADV_TRANS_GOAL|ADV_TRANS_ACTIVE);
193439217Sgibbs
193539217Sgibbs		/* Offset too high or large period forced async */
193639217Sgibbs		if (orig_offset != ext_msg.req_ack_offset)
193739217Sgibbs			sdtr_accept = FALSE;
193839217Sgibbs
193939217Sgibbs		if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
194039217Sgibbs			/* Valid response to our requested negotiation */
194139217Sgibbs			q_cntl &= ~QC_MSG_OUT;
194239217Sgibbs		} else {
194339217Sgibbs			/* Must Respond */
194439217Sgibbs			q_cntl |= QC_MSG_OUT;
194539217Sgibbs			adv_msgout_sdtr(adv, ext_msg.xfer_period,
194639217Sgibbs					ext_msg.req_ack_offset);
194739217Sgibbs		}
194839217Sgibbs
194939217Sgibbs	} else if (ext_msg.msg_type == MSG_EXTENDED
195039217Sgibbs		&& ext_msg.msg_req == MSG_EXT_WDTR
195139217Sgibbs		&& ext_msg.msg_len == MSG_EXT_WDTR_LEN) {
195239217Sgibbs
195339217Sgibbs		ext_msg.wdtr_width = 0;
195439217Sgibbs		adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG,
195539217Sgibbs					(u_int16_t *)&ext_msg,
195639217Sgibbs					sizeof(ext_msg) >> 1);
195739217Sgibbs		q_cntl |= QC_MSG_OUT;
195839217Sgibbs        } else {
195939217Sgibbs
196039217Sgibbs		ext_msg.msg_type = MSG_MESSAGE_REJECT;
196139217Sgibbs		adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG,
196239217Sgibbs					(u_int16_t *)&ext_msg,
196339217Sgibbs					sizeof(ext_msg) >> 1);
196439217Sgibbs		q_cntl |= QC_MSG_OUT;
196539217Sgibbs        }
196639217Sgibbs	adv_write_lram_8(adv, halt_q_addr + ADV_SCSIQ_B_CNTL, q_cntl);
196739217Sgibbs}
196839217Sgibbs
196939217Sgibbsstatic void
197039217Sgibbsadv_msgout_sdtr(struct adv_softc *adv, u_int8_t sdtr_period,
197139217Sgibbs		u_int8_t sdtr_offset)
197239217Sgibbs{
197339217Sgibbs	struct	 ext_msg sdtr_buf;
197439217Sgibbs
197518781Sgibbs	sdtr_buf.msg_type = MSG_EXTENDED;
197618781Sgibbs	sdtr_buf.msg_len = MSG_EXT_SDTR_LEN;
197718781Sgibbs	sdtr_buf.msg_req = MSG_EXT_SDTR;
197818781Sgibbs	sdtr_buf.xfer_period = sdtr_period;
197918781Sgibbs	sdtr_offset &= ADV_SYN_MAX_OFFSET;
198018781Sgibbs	sdtr_buf.req_ack_offset = sdtr_offset;
198118781Sgibbs	adv_write_lram_16_multi(adv, ADVV_MSGOUT_BEG,
198218781Sgibbs				(u_int16_t *) &sdtr_buf,
198318781Sgibbs				sizeof(sdtr_buf) / 2);
198418781Sgibbs}
198518781Sgibbs
198639217Sgibbsint
198739217Sgibbsadv_abort_ccb(struct adv_softc *adv, int target, int lun, union ccb *ccb,
198839217Sgibbs	      u_int32_t status, int queued_only)
198918781Sgibbs{
199039217Sgibbs	u_int16_t q_addr;
199139217Sgibbs	u_int8_t  q_no;
199239217Sgibbs	struct adv_q_done_info scsiq_buf;
199339217Sgibbs	struct adv_q_done_info *scsiq;
199439217Sgibbs	u_int8_t  target_ix;
199539217Sgibbs	int	  count;
199618781Sgibbs
199739217Sgibbs	scsiq = &scsiq_buf;
199839217Sgibbs	target_ix = ADV_TIDLUN_TO_IX(target, lun);
199939217Sgibbs	count = 0;
200039217Sgibbs	for (q_no = ADV_MIN_ACTIVE_QNO; q_no <= adv->max_openings; q_no++) {
200155945Sgibbs		struct adv_ccb_info *ccb_info;
200239217Sgibbs		q_addr = ADV_QNO_TO_QADDR(q_no);
200339217Sgibbs
200439217Sgibbs		adv_copy_lram_doneq(adv, q_addr, scsiq, adv->max_dma_count);
200555945Sgibbs		ccb_info = &adv->ccb_infos[scsiq->d2.ccb_index];
200639217Sgibbs		if (((scsiq->q_status & QS_READY) != 0)
200739217Sgibbs		 && ((scsiq->q_status & QS_ABORTED) == 0)
200839217Sgibbs		 && ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)
200939217Sgibbs		 && (scsiq->d2.target_ix == target_ix)
201039217Sgibbs		 && (queued_only == 0
201139217Sgibbs		  || !(scsiq->q_status & (QS_DISC1|QS_DISC2|QS_BUSY|QS_DONE)))
201255945Sgibbs		 && (ccb == NULL || (ccb == ccb_info->ccb))) {
201339217Sgibbs			union ccb *aborted_ccb;
201439217Sgibbs			struct adv_ccb_info *cinfo;
201539217Sgibbs
201639217Sgibbs			scsiq->q_status |= QS_ABORTED;
201739217Sgibbs			adv_write_lram_8(adv, q_addr + ADV_SCSIQ_B_STATUS,
201839217Sgibbs					 scsiq->q_status);
201955945Sgibbs			aborted_ccb = ccb_info->ccb;
202039217Sgibbs			/* Don't clobber earlier error codes */
202139217Sgibbs			if ((aborted_ccb->ccb_h.status & CAM_STATUS_MASK)
202239217Sgibbs			  == CAM_REQ_INPROG)
202339217Sgibbs				aborted_ccb->ccb_h.status |= status;
202439217Sgibbs			cinfo = (struct adv_ccb_info *)
202539217Sgibbs			    aborted_ccb->ccb_h.ccb_cinfo_ptr;
202639217Sgibbs			cinfo->state |= ACCB_ABORT_QUEUED;
202739217Sgibbs			count++;
202818781Sgibbs		}
202918781Sgibbs	}
203039217Sgibbs	return (count);
203118781Sgibbs}
203218781Sgibbs
203339217Sgibbsint
203455945Sgibbsadv_reset_bus(struct adv_softc *adv, int initiate_bus_reset)
203539217Sgibbs{
203639217Sgibbs	int count;
203739217Sgibbs	int i;
203839217Sgibbs	union ccb *ccb;
203939217Sgibbs
204055945Sgibbs	i = 200;
204155945Sgibbs	while ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_SCSI_RESET_ACTIVE) != 0
204255945Sgibbs	    && i--)
204355945Sgibbs		DELAY(1000);
204455945Sgibbs	adv_reset_chip(adv, initiate_bus_reset);
204539217Sgibbs	adv_reinit_lram(adv);
204655945Sgibbs	for (i = 0; i <= ADV_MAX_TID; i++)
204755945Sgibbs		adv_set_syncrate(adv, NULL, i, /*period*/0,
204855945Sgibbs				 /*offset*/0, ADV_TRANS_CUR);
204939217Sgibbs	ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR);
205039217Sgibbs
205139217Sgibbs	/* Tell the XPT layer that a bus reset occured */
205239217Sgibbs	if (adv->path != NULL)
205339217Sgibbs		xpt_async(AC_BUS_RESET, adv->path, NULL);
205439217Sgibbs
205539217Sgibbs	count = 0;
205639217Sgibbs	while ((ccb = (union ccb *)LIST_FIRST(&adv->pending_ccbs)) != NULL) {
205739217Sgibbs		if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG)
205839217Sgibbs			ccb->ccb_h.status |= CAM_SCSI_BUS_RESET;
205939217Sgibbs		adv_done(adv, ccb, QD_ABORTED_BY_HOST, 0, 0, 0);
206039217Sgibbs		count++;
206139217Sgibbs	}
206239217Sgibbs
206339217Sgibbs	adv_start_chip(adv);
206439217Sgibbs	return (count);
206539217Sgibbs}
206639217Sgibbs
206718781Sgibbsstatic void
206839217Sgibbsadv_set_sdtr_reg_at_id(struct adv_softc *adv, int tid, u_int8_t sdtr_data)
206918781Sgibbs{
207039217Sgibbs	int orig_id;
207139217Sgibbs
207239217Sgibbs    	adv_set_bank(adv, 1);
207339217Sgibbs    	orig_id = ffs(ADV_INB(adv, ADV_HOST_SCSIID)) - 1;
207439217Sgibbs    	ADV_OUTB(adv, ADV_HOST_SCSIID, tid);
207539217Sgibbs	if (ADV_INB(adv, ADV_HOST_SCSIID) == (0x01 << tid)) {
207639217Sgibbs		adv_set_bank(adv, 0);
207739217Sgibbs		ADV_OUTB(adv, ADV_SYN_OFFSET, sdtr_data);
207839217Sgibbs	}
207939217Sgibbs    	adv_set_bank(adv, 1);
208039217Sgibbs    	ADV_OUTB(adv, ADV_HOST_SCSIID, orig_id);
208139217Sgibbs	adv_set_bank(adv, 0);
208218781Sgibbs}
2083