aha.c revision 47208
139225Sgibbs/*
239225Sgibbs * Generic register and struct definitions for the Adaptech 154x/164x
339225Sgibbs * SCSI host adapters. Product specific probe and attach routines can
439225Sgibbs * be found in:
539751Simp *      aha 1540/1542B/1542C/1542CF/1542CP	aha_isa.c
639225Sgibbs *
739751Simp * Copyright (c) 1998 M. Warner Losh.
839751Simp * All Rights Reserved.
939751Simp *
1039751Simp *
1139751Simp * Redistribution and use in source and binary forms, with or without
1239751Simp * modification, are permitted provided that the following conditions
1339751Simp * are met:
1439751Simp * 1. Redistributions of source code must retain the above copyright
1539751Simp *    notice, this list of conditions, and the following disclaimer,
1639751Simp *    without modification, immediately at the beginning of the file.
1739751Simp * 2. The name of the author may not be used to endorse or promote products
1839751Simp *    derived from this software without specific prior written permission.
1939751Simp *
2039751Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2139751Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2239751Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2339751Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2439751Simp * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2539751Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2639751Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2739751Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2839751Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2939751Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3039751Simp * SUCH DAMAGE.
3139751Simp *
3239225Sgibbs * Derived from bt.c written by:
3339225Sgibbs *
3439225Sgibbs * Copyright (c) 1998 Justin T. Gibbs.
3539225Sgibbs * All rights reserved.
3639225Sgibbs *
3739225Sgibbs * Redistribution and use in source and binary forms, with or without
3839225Sgibbs * modification, are permitted provided that the following conditions
3939225Sgibbs * are met:
4039225Sgibbs * 1. Redistributions of source code must retain the above copyright
4139225Sgibbs *    notice, this list of conditions, and the following disclaimer,
4239225Sgibbs *    without modification, immediately at the beginning of the file.
4339225Sgibbs * 2. The name of the author may not be used to endorse or promote products
4439225Sgibbs *    derived from this software without specific prior written permission.
4539225Sgibbs *
4639225Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
4739225Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4839225Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4939225Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
5039225Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5139225Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5239225Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5339225Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5439225Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5539225Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5639225Sgibbs * SUCH DAMAGE.
5739225Sgibbs *
5847208Simp *      $Id: aha.c,v 1.24 1999/05/11 08:12:11 imp Exp $
5939225Sgibbs */
6039225Sgibbs
6142887Simp#include "pnp.h"
6242887Simp
6339225Sgibbs#include <sys/param.h>
6439225Sgibbs#include <sys/systm.h>
6539225Sgibbs#include <sys/malloc.h>
6639225Sgibbs#include <sys/buf.h>
6739225Sgibbs#include <sys/kernel.h>
6839225Sgibbs#include <sys/sysctl.h>
6939225Sgibbs
7039225Sgibbs#include <machine/bus_pio.h>
7139225Sgibbs#include <machine/bus.h>
7239225Sgibbs#include <machine/clock.h>
7339225Sgibbs
7439225Sgibbs#include <cam/cam.h>
7539225Sgibbs#include <cam/cam_ccb.h>
7639225Sgibbs#include <cam/cam_sim.h>
7739225Sgibbs#include <cam/cam_xpt_sim.h>
7839225Sgibbs#include <cam/cam_debug.h>
7939225Sgibbs
8039225Sgibbs#include <cam/scsi/scsi_message.h>
8139225Sgibbs
8239225Sgibbs#include <vm/vm.h>
8339225Sgibbs#include <vm/pmap.h>
8442887Simp
8542887Simp#if NPNP > 0
8642887Simp#include <i386/isa/isa_device.h>
8742887Simp#include <i386/isa/pnp.h>		/* XXX pnp isn't x86 only */
8842887Simp#endif
8939225Sgibbs
9039225Sgibbs#include <dev/aha/ahareg.h>
9139225Sgibbs
9242887Simpstruct aha_softc *aha_softcs[NAHATOT];
9339225Sgibbs
9439225Sgibbs#define MIN(a, b) ((a) < (b) ? (a) : (b))
9539881Simp#define	PRVERB(x) if (bootverbose) printf x
9639225Sgibbs
9739751Simp/* Macro to determine that a rev is potentially a new valid one
9839751Simp * so that the driver doesn't keep breaking on new revs as it
9939751Simp * did for the CF and CP.
10039751Simp */
10139751Simp#define PROBABLY_NEW_BOARD(REV) (REV > 0x43 && REV < 0x56)
10239751Simp
10339225Sgibbs/* MailBox Management functions */
10439225Sgibbsstatic __inline void	ahanextinbox(struct aha_softc *aha);
10539225Sgibbsstatic __inline void	ahanextoutbox(struct aha_softc *aha);
10639225Sgibbs
10739225Sgibbsstatic __inline void
10839225Sgibbsahanextinbox(struct aha_softc *aha)
10939225Sgibbs{
11039225Sgibbs	if (aha->cur_inbox == aha->last_inbox)
11139225Sgibbs		aha->cur_inbox = aha->in_boxes;
11239225Sgibbs	else
11339225Sgibbs		aha->cur_inbox++;
11439225Sgibbs}
11539225Sgibbs
11639225Sgibbsstatic __inline void
11739225Sgibbsahanextoutbox(struct aha_softc *aha)
11839225Sgibbs{
11939225Sgibbs	if (aha->cur_outbox == aha->last_outbox)
12039225Sgibbs		aha->cur_outbox = aha->out_boxes;
12139225Sgibbs	else
12239225Sgibbs		aha->cur_outbox++;
12339225Sgibbs}
12439225Sgibbs
12539225Sgibbs#define ahautoa24(u,s3)			\
12639225Sgibbs	(s3)[0] = ((u) >> 16) & 0xff;	\
12739225Sgibbs	(s3)[1] = ((u) >> 8) & 0xff;	\
12839225Sgibbs	(s3)[2] = (u) & 0xff;
12939225Sgibbs
13039225Sgibbs#define aha_a24tou(s3) \
13139225Sgibbs	(((s3)[0] << 16) | ((s3)[1] << 8) | (s3)[2])
13239225Sgibbs
13339225Sgibbs/* CCB Mangement functions */
13439225Sgibbsstatic __inline u_int32_t		ahaccbvtop(struct aha_softc *aha,
13541047Sgibbs						  struct aha_ccb *accb);
13639225Sgibbsstatic __inline struct aha_ccb*		ahaccbptov(struct aha_softc *aha,
13739225Sgibbs						  u_int32_t ccb_addr);
13839225Sgibbs
13939225Sgibbsstatic __inline u_int32_t
14041047Sgibbsahaccbvtop(struct aha_softc *aha, struct aha_ccb *accb)
14139225Sgibbs{
14239225Sgibbs	return (aha->aha_ccb_physbase
14341047Sgibbs	      + (u_int32_t)((caddr_t)accb - (caddr_t)aha->aha_ccb_array));
14439225Sgibbs}
14539225Sgibbsstatic __inline struct aha_ccb *
14639225Sgibbsahaccbptov(struct aha_softc *aha, u_int32_t ccb_addr)
14739225Sgibbs{
14839225Sgibbs	return (aha->aha_ccb_array +
14939225Sgibbs	      + ((struct aha_ccb*)ccb_addr-(struct aha_ccb*)aha->aha_ccb_physbase));
15039225Sgibbs}
15139225Sgibbs
15239225Sgibbsstatic struct aha_ccb*	ahagetccb(struct aha_softc *aha);
15341047Sgibbsstatic __inline void	ahafreeccb(struct aha_softc *aha, struct aha_ccb *accb);
15439225Sgibbsstatic void		ahaallocccbs(struct aha_softc *aha);
15539225Sgibbsstatic bus_dmamap_callback_t ahaexecuteccb;
15641047Sgibbsstatic void		ahadone(struct aha_softc *aha, struct aha_ccb *accb,
15739225Sgibbs			       aha_mbi_comp_code_t comp_code);
15839225Sgibbs
15939225Sgibbs/* Host adapter command functions */
16039225Sgibbsstatic int	ahareset(struct aha_softc* aha, int hard_reset);
16139225Sgibbs
16239225Sgibbs/* Initialization functions */
16339225Sgibbsstatic int			ahainitmboxes(struct aha_softc *aha);
16439225Sgibbsstatic bus_dmamap_callback_t	ahamapmboxes;
16539225Sgibbsstatic bus_dmamap_callback_t	ahamapccbs;
16639225Sgibbsstatic bus_dmamap_callback_t	ahamapsgs;
16739225Sgibbs
16839225Sgibbs/* Transfer Negotiation Functions */
16939225Sgibbsstatic void ahafetchtransinfo(struct aha_softc *aha,
17039225Sgibbs			     struct ccb_trans_settings *cts);
17139225Sgibbs
17239225Sgibbs/* CAM SIM entry points */
17341047Sgibbs#define ccb_accb_ptr spriv_ptr0
17439225Sgibbs#define ccb_aha_ptr spriv_ptr1
17539225Sgibbsstatic void	ahaaction(struct cam_sim *sim, union ccb *ccb);
17639225Sgibbsstatic void	ahapoll(struct cam_sim *sim);
17739225Sgibbs
17839225Sgibbs/* Our timeout handler */
17946602Speterstatic timeout_t ahatimeout;
18039225Sgibbs
18139225Sgibbsu_long aha_unit = 0;
18239225Sgibbs
18339225Sgibbs/*
18439225Sgibbs * Do our own re-probe protection until a configuration
18539225Sgibbs * manager can do it for us.  This ensures that we don't
18639225Sgibbs * reprobe a card already found by the EISA or PCI probes.
18739225Sgibbs */
18845575Seivindstatic struct aha_isa_port aha_isa_ports[] =
18939225Sgibbs{
19041047Sgibbs	{ 0x130, 0, 4 },
19141047Sgibbs	{ 0x134, 0, 5 },
19241047Sgibbs	{ 0x230, 0, 2 },
19341047Sgibbs	{ 0x234, 0, 3 },
19441047Sgibbs	{ 0x330, 0, 0 },
19541047Sgibbs	{ 0x334, 0, 1 }
19639225Sgibbs};
19739225Sgibbs
19841047Sgibbs/*
19941047Sgibbs * I/O ports listed in the order enumerated by the
20041047Sgibbs * card for certain op codes.
20141047Sgibbs */
20245575Seivindstatic u_int16_t aha_board_ports[] =
20341047Sgibbs{
20441047Sgibbs	0x330,
20541047Sgibbs	0x334,
20641047Sgibbs	0x230,
20741047Sgibbs	0x234,
20841047Sgibbs	0x130,
20941047Sgibbs	0x134
21041047Sgibbs};
21141047Sgibbs
21239225Sgibbs/* Exported functions */
21339225Sgibbsstruct aha_softc *
21439225Sgibbsaha_alloc(int unit, bus_space_tag_t tag, bus_space_handle_t bsh)
21539225Sgibbs{
21639225Sgibbs	struct  aha_softc *aha;
21739225Sgibbs
21839225Sgibbs	if (unit != AHA_TEMP_UNIT) {
21942887Simp		if (unit >= NAHATOT) {
22039225Sgibbs			printf("aha: unit number (%d) too high\n", unit);
22139225Sgibbs			return NULL;
22239225Sgibbs		}
22339225Sgibbs
22439225Sgibbs		/*
22539225Sgibbs		 * Allocate a storage area for us
22639225Sgibbs		 */
22739225Sgibbs		if (aha_softcs[unit]) {
22839225Sgibbs			printf("aha%d: memory already allocated\n", unit);
22939225Sgibbs			return NULL;
23039225Sgibbs		}
23139225Sgibbs	}
23239225Sgibbs
23339225Sgibbs	aha = malloc(sizeof(struct aha_softc), M_DEVBUF, M_NOWAIT);
23439225Sgibbs	if (!aha) {
23539225Sgibbs		printf("aha%d: cannot malloc!\n", unit);
23639225Sgibbs		return NULL;
23739225Sgibbs	}
23839225Sgibbs	bzero(aha, sizeof(struct aha_softc));
23939225Sgibbs	SLIST_INIT(&aha->free_aha_ccbs);
24039225Sgibbs	LIST_INIT(&aha->pending_ccbs);
24139225Sgibbs	SLIST_INIT(&aha->sg_maps);
24239225Sgibbs	aha->unit = unit;
24339225Sgibbs	aha->tag = tag;
24439225Sgibbs	aha->bsh = bsh;
24542887Simp	aha->ccb_sg_opcode = INITIATOR_SG_CCB_WRESID;
24642887Simp	aha->ccb_ccb_opcode = INITIATOR_CCB_WRESID;
24739225Sgibbs
24839225Sgibbs	if (aha->unit != AHA_TEMP_UNIT) {
24939225Sgibbs		aha_softcs[unit] = aha;
25039225Sgibbs	}
25139225Sgibbs	return (aha);
25239225Sgibbs}
25339225Sgibbs
25439225Sgibbsvoid
25539225Sgibbsaha_free(struct aha_softc *aha)
25639225Sgibbs{
25739225Sgibbs	switch (aha->init_level) {
25839225Sgibbs	default:
25939225Sgibbs	case 8:
26039225Sgibbs	{
26139225Sgibbs		struct sg_map_node *sg_map;
26239225Sgibbs
26339225Sgibbs		while ((sg_map = SLIST_FIRST(&aha->sg_maps))!= NULL) {
26439225Sgibbs			SLIST_REMOVE_HEAD(&aha->sg_maps, links);
26539225Sgibbs			bus_dmamap_unload(aha->sg_dmat,
26639225Sgibbs					  sg_map->sg_dmamap);
26739225Sgibbs			bus_dmamem_free(aha->sg_dmat, sg_map->sg_vaddr,
26839225Sgibbs					sg_map->sg_dmamap);
26939225Sgibbs			free(sg_map, M_DEVBUF);
27039225Sgibbs		}
27139225Sgibbs		bus_dma_tag_destroy(aha->sg_dmat);
27239225Sgibbs	}
27339225Sgibbs	case 7:
27439225Sgibbs		bus_dmamap_unload(aha->ccb_dmat, aha->ccb_dmamap);
27539225Sgibbs	case 6:
27639225Sgibbs		bus_dmamap_destroy(aha->ccb_dmat, aha->ccb_dmamap);
27739225Sgibbs		bus_dmamem_free(aha->ccb_dmat, aha->aha_ccb_array,
27839225Sgibbs				aha->ccb_dmamap);
27939225Sgibbs	case 5:
28039225Sgibbs		bus_dma_tag_destroy(aha->ccb_dmat);
28139225Sgibbs	case 4:
28239225Sgibbs		bus_dmamap_unload(aha->mailbox_dmat, aha->mailbox_dmamap);
28339225Sgibbs	case 3:
28439225Sgibbs		bus_dmamem_free(aha->mailbox_dmat, aha->in_boxes,
28539225Sgibbs				aha->mailbox_dmamap);
28639225Sgibbs		bus_dmamap_destroy(aha->mailbox_dmat, aha->mailbox_dmamap);
28739225Sgibbs	case 2:
28839225Sgibbs		bus_dma_tag_destroy(aha->buffer_dmat);
28939225Sgibbs	case 1:
29039225Sgibbs		bus_dma_tag_destroy(aha->mailbox_dmat);
29139225Sgibbs	case 0:
29239225Sgibbs	}
29339225Sgibbs	if (aha->unit != AHA_TEMP_UNIT) {
29439225Sgibbs		aha_softcs[aha->unit] = NULL;
29539225Sgibbs	}
29639225Sgibbs	free(aha, M_DEVBUF);
29739225Sgibbs}
29839225Sgibbs
29939225Sgibbs/*
30039225Sgibbs * Probe the adapter and verify that the card is an Adaptec.
30139225Sgibbs */
30239225Sgibbsint
30339225Sgibbsaha_probe(struct aha_softc* aha)
30439225Sgibbs{
30539225Sgibbs	u_int	 status;
30639225Sgibbs	u_int	 intstat;
30739225Sgibbs	int	 error;
30839852Simp	board_id_data_t	board_id;
30939225Sgibbs
31039225Sgibbs	/*
31139225Sgibbs	 * See if the three I/O ports look reasonable.
31239225Sgibbs	 * Touch the minimal number of registers in the
31339225Sgibbs	 * failure case.
31439225Sgibbs	 */
31539225Sgibbs	status = aha_inb(aha, STATUS_REG);
31639225Sgibbs	if ((status == 0)
31739225Sgibbs	 || (status & (DIAG_ACTIVE|CMD_REG_BUSY|
31841047Sgibbs		       STATUS_REG_RSVD)) != 0) {
31941047Sgibbs		PRVERB(("%s: status reg test failed %x\n", aha_name(aha),
32041047Sgibbs			status));
32139225Sgibbs		return (ENXIO);
32239225Sgibbs	}
32339225Sgibbs
32439225Sgibbs	intstat = aha_inb(aha, INTSTAT_REG);
32539225Sgibbs	if ((intstat & INTSTAT_REG_RSVD) != 0) {
32641047Sgibbs		PRVERB(("%s: Failed Intstat Reg Test\n", aha_name(aha)));
32739225Sgibbs		return (ENXIO);
32839225Sgibbs	}
32939225Sgibbs
33039225Sgibbs	/*
33141047Sgibbs	 * Looking good so far.  Final test is to reset the
33241047Sgibbs	 * adapter and fetch the board ID and ensure we aren't
33341047Sgibbs	 * looking at a BusLogic.
33441047Sgibbs	 */
33541047Sgibbs	if ((error = ahareset(aha, /*hard_reset*/TRUE)) != 0) {
33641047Sgibbs		if (bootverbose)
33741047Sgibbs			printf("%s: Failed Reset\n", aha_name(aha));
33841047Sgibbs		return (ENXIO);
33941047Sgibbs	}
34041047Sgibbs
34141047Sgibbs	/*
34239852Simp	 * Get the board ID.  We use this to see if we're dealing with
34339852Simp	 * a buslogic card or a aha card (or clone).
34439225Sgibbs	 */
34541047Sgibbs	error = aha_cmd(aha, AOP_INQUIRE_BOARD_ID, NULL, /*parmlen*/0,
34639852Simp		       (u_int8_t*)&board_id, sizeof(board_id),
34739852Simp		       DEFAULT_CMD_TIMEOUT);
34839852Simp	if (error != 0) {
34939881Simp		PRVERB(("%s: INQUIRE failed %x\n", aha_name(aha), error));
35039225Sgibbs		return (ENXIO);
35139225Sgibbs	}
35239852Simp	aha->fw_major = board_id.firmware_rev_major;
35339852Simp	aha->fw_minor = board_id.firmware_rev_minor;
35439852Simp	aha->boardid = board_id.board_type;
35539852Simp
35639225Sgibbs	/*
35739852Simp	 * The Buslogic cards have an id of either 0x41 or 0x42.  So
35839852Simp	 * if those come up in the probe, we test the geometry register
35939852Simp	 * of the board.  Adaptec boards that are this old will not have
36039852Simp	 * this register, and return 0xff, while buslogic cards will return
36139852Simp	 * something different.
36239852Simp	 *
36341335Simp	 * It appears that for reasons unknow, for the for the
36441335Simp	 * aha-1542B cards, we need to wait a little bit before trying
36541335Simp	 * to read the geometry register.  I picked 10ms since we have
36641335Simp	 * reports that a for loop to 1000 did the trick, and this
36741335Simp	 * errs on the side of conservatism.  Besides, no one will
36841335Simp	 * notice a 10mS delay here, even the 1542B card users :-)
36941335Simp	 *
37046997Simp	 * Some compatible cards return 0 here.  Some cards also
37146997Simp	 * seem to return 0x7f.
37241807Simp	 *
37341335Simp	 * XXX I'm not sure how this will impact other cloned cards
37441807Simp	 *
37541807Simp	 * This really should be replaced with the esetup command, since
37646997Simp	 * that appears to be more reliable.  This becomes more and more
37746997Simp	 * true over time as we discover more cards that don't read the
37846997Simp	 * geometry register consistantly.
37939225Sgibbs	 */
38039852Simp	if (aha->boardid <= 0x42) {
38141335Simp		/* Wait 10ms before reading */
38241335Simp		DELAY(10000);
38339852Simp		status = aha_inb(aha, GEOMETRY_REG);
38446997Simp		if (status != 0xff && status != 0x00 && status != 0x7f) {
38544434Simp			PRVERB(("%s: Geometry Register test failed 0x%x\n",
38644434Simp				aha_name(aha), status));
38739852Simp			return (ENXIO);
38841047Sgibbs		}
38939751Simp	}
39039852Simp
39139225Sgibbs	return (0);
39239225Sgibbs}
39339225Sgibbs
39439225Sgibbs/*
39539225Sgibbs * Pull the boards setup information and record it in our softc.
39639225Sgibbs */
39739225Sgibbsint
39839225Sgibbsaha_fetch_adapter_info(struct aha_softc *aha)
39939225Sgibbs{
40039225Sgibbs	setup_data_t	setup_info;
40139225Sgibbs	config_data_t config_data;
40239225Sgibbs	u_int8_t length_param;
40339225Sgibbs	int	 error;
40439751Simp	struct	aha_extbios extbios;
40539225Sgibbs
40639852Simp	switch (aha->boardid) {
40739225Sgibbs	case BOARD_1540_16HEAD_BIOS:
40841514Sarchie		snprintf(aha->model, sizeof(aha->model), "1540 16 head BIOS");
40939225Sgibbs		break;
41039225Sgibbs	case BOARD_1540_64HEAD_BIOS:
41141514Sarchie		snprintf(aha->model, sizeof(aha->model), "1540 64 head BIOS");
41239225Sgibbs		break;
41339225Sgibbs	case BOARD_1542:
41441514Sarchie		snprintf(aha->model, sizeof(aha->model), "1540/1542 64 head BIOS");
41539225Sgibbs		break;
41639225Sgibbs	case BOARD_1640:
41741514Sarchie		snprintf(aha->model, sizeof(aha->model), "1640");
41839225Sgibbs		break;
41939225Sgibbs	case BOARD_1740:
42041514Sarchie		snprintf(aha->model, sizeof(aha->model), "1740A/1742A/1744");
42139225Sgibbs		break;
42239225Sgibbs	case BOARD_1542C:
42341514Sarchie		snprintf(aha->model, sizeof(aha->model), "1542C");
42439225Sgibbs		break;
42539225Sgibbs	case BOARD_1542CF:
42641514Sarchie		snprintf(aha->model, sizeof(aha->model), "1542CF");
42739225Sgibbs		break;
42839225Sgibbs	case BOARD_1542CP:
42941514Sarchie		snprintf(aha->model, sizeof(aha->model), "1542CP");
43039225Sgibbs		break;
43139225Sgibbs	default:
43241514Sarchie		snprintf(aha->model, sizeof(aha->model), "Unknown");
43339225Sgibbs		break;
43439225Sgibbs	}
43539751Simp	/*
43639751Simp	 * If we are a new type of 1542 board (anything newer than a 1542C)
43739751Simp	 * then disable the extended bios so that the
43839751Simp	 * mailbox interface is unlocked.
43939751Simp	 * This is also true for the 1542B Version 3.20. First Adaptec
44039751Simp	 * board that supports >1Gb drives.
44139751Simp	 * No need to check the extended bios flags as some of the
44239751Simp	 * extensions that cause us problems are not flagged in that byte.
44339751Simp	 */
44439751Simp	if (PROBABLY_NEW_BOARD(aha->boardid) ||
44539751Simp		(aha->boardid == 0x41
44639852Simp		&& aha->fw_major == 0x31 &&
44739852Simp		aha->fw_minor >= 0x34)) {
44841047Sgibbs		error = aha_cmd(aha, AOP_RETURN_EXT_BIOS_INFO, NULL,
44939751Simp			/*paramlen*/0, (u_char *)&extbios, sizeof(extbios),
45039751Simp			DEFAULT_CMD_TIMEOUT);
45141047Sgibbs		error = aha_cmd(aha, AOP_MBOX_IF_ENABLE, (u_int8_t *)&extbios,
45239751Simp			/*paramlen*/2, NULL, 0, DEFAULT_CMD_TIMEOUT);
45339751Simp	}
45439751Simp	if (aha->boardid < 0x41)
45541335Simp		printf("%s: Warning: aha-1542A won't likely work.\n",
45639751Simp			aha_name(aha));
45739751Simp
45841335Simp	aha->max_sg = 17;		/* Need >= 17 to do 64k I/O */
45939225Sgibbs	aha->diff_bus = 0;
46039225Sgibbs	aha->extended_lun = 0;
46139751Simp	aha->extended_trans = 0;
46240403Simp	aha->max_ccbs = 16;
46339225Sgibbs	/* Determine Sync/Wide/Disc settings */
46439225Sgibbs	length_param = sizeof(setup_info);
46541047Sgibbs	error = aha_cmd(aha, AOP_INQUIRE_SETUP_INFO, &length_param,
46639225Sgibbs		       /*paramlen*/1, (u_int8_t*)&setup_info,
46739225Sgibbs		       sizeof(setup_info), DEFAULT_CMD_TIMEOUT);
46839225Sgibbs	if (error != 0) {
46939225Sgibbs		printf("%s: aha_fetch_adapter_info - Failed "
47039225Sgibbs		       "Get Setup Info\n", aha_name(aha));
47139225Sgibbs		return (error);
47239225Sgibbs	}
47339225Sgibbs	if (setup_info.initiate_sync != 0) {
47439225Sgibbs		aha->sync_permitted = ALL_TARGETS;
47539225Sgibbs	}
47639225Sgibbs	aha->disc_permitted = ALL_TARGETS;
47739225Sgibbs
47839225Sgibbs	/* We need as many mailboxes as we can have ccbs */
47939225Sgibbs	aha->num_boxes = aha->max_ccbs;
48039225Sgibbs
48139225Sgibbs	/* Determine our SCSI ID */
48239225Sgibbs
48341047Sgibbs	error = aha_cmd(aha, AOP_INQUIRE_CONFIG, NULL, /*parmlen*/0,
48439225Sgibbs		       (u_int8_t*)&config_data, sizeof(config_data),
48539225Sgibbs		       DEFAULT_CMD_TIMEOUT);
48639225Sgibbs	if (error != 0) {
48739225Sgibbs		printf("%s: aha_fetch_adapter_info - Failed Get Config\n",
48839225Sgibbs		       aha_name(aha));
48939225Sgibbs		return (error);
49039225Sgibbs	}
49139225Sgibbs	aha->scsi_id = config_data.scsi_id;
49239225Sgibbs	return (0);
49339225Sgibbs}
49439225Sgibbs
49539225Sgibbs/*
49639225Sgibbs * Start the board, ready for normal operation
49739225Sgibbs */
49839225Sgibbsint
49939225Sgibbsaha_init(struct aha_softc* aha)
50039225Sgibbs{
50139225Sgibbs	/* Announce the Adapter */
50239852Simp	printf("%s: AHA-%s FW Rev. %c.%c (ID=%x) ", aha_name(aha),
50339852Simp	       aha->model, aha->fw_major, aha->fw_minor, aha->boardid);
50439225Sgibbs
50539225Sgibbs	if (aha->diff_bus != 0)
50639225Sgibbs		printf("Diff ");
50739225Sgibbs
50839225Sgibbs	printf("SCSI Host Adapter, SCSI ID %d, %d CCBs\n", aha->scsi_id,
50939225Sgibbs	       aha->max_ccbs);
51039225Sgibbs
51139225Sgibbs	/*
51239225Sgibbs	 * Create our DMA tags.  These tags define the kinds of device
51339225Sgibbs	 * accessable memory allocations and memory mappings we will
51439225Sgibbs	 * need to perform during normal operation.
51539225Sgibbs	 *
51639225Sgibbs	 * Unless we need to further restrict the allocation, we rely
51739225Sgibbs	 * on the restrictions of the parent dmat, hence the common
51839225Sgibbs	 * use of MAXADDR and MAXSIZE.
51939225Sgibbs	 */
52039225Sgibbs
52139225Sgibbs	/* DMA tag for mapping buffers into device visible space. */
52239225Sgibbs	if (bus_dma_tag_create(aha->parent_dmat, /*alignment*/0, /*boundary*/0,
52339225Sgibbs			       /*lowaddr*/BUS_SPACE_MAXADDR,
52439225Sgibbs			       /*highaddr*/BUS_SPACE_MAXADDR,
52539225Sgibbs			       /*filter*/NULL, /*filterarg*/NULL,
52639225Sgibbs			       /*maxsize*/MAXBSIZE, /*nsegments*/AHA_NSEG,
52739225Sgibbs			       /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT,
52839225Sgibbs			       /*flags*/BUS_DMA_ALLOCNOW,
52939225Sgibbs			       &aha->buffer_dmat) != 0) {
53039225Sgibbs		goto error_exit;
53139225Sgibbs	}
53239225Sgibbs
53339225Sgibbs	aha->init_level++;
53439225Sgibbs	/* DMA tag for our mailboxes */
53539225Sgibbs	if (bus_dma_tag_create(aha->parent_dmat, /*alignment*/0, /*boundary*/0,
53639225Sgibbs			       /*lowaddr*/BUS_SPACE_MAXADDR,
53739225Sgibbs			       /*highaddr*/BUS_SPACE_MAXADDR,
53839225Sgibbs			       /*filter*/NULL, /*filterarg*/NULL,
53939225Sgibbs			       aha->num_boxes * (sizeof(aha_mbox_in_t)
54039225Sgibbs					       + sizeof(aha_mbox_out_t)),
54139225Sgibbs			       /*nsegments*/1,
54239225Sgibbs			       /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT,
54339225Sgibbs			       /*flags*/0, &aha->mailbox_dmat) != 0) {
54439225Sgibbs		goto error_exit;
54539225Sgibbs        }
54639225Sgibbs
54739225Sgibbs	aha->init_level++;
54839225Sgibbs
54939225Sgibbs	/* Allocation for our mailboxes */
55039225Sgibbs	if (bus_dmamem_alloc(aha->mailbox_dmat, (void **)&aha->out_boxes,
55139225Sgibbs			     BUS_DMA_NOWAIT, &aha->mailbox_dmamap) != 0) {
55239225Sgibbs		goto error_exit;
55339225Sgibbs	}
55439225Sgibbs
55539225Sgibbs	aha->init_level++;
55639225Sgibbs
55739225Sgibbs	/* And permanently map them */
55839225Sgibbs	bus_dmamap_load(aha->mailbox_dmat, aha->mailbox_dmamap,
55939225Sgibbs       			aha->out_boxes,
56039225Sgibbs			aha->num_boxes * (sizeof(aha_mbox_in_t)
56139225Sgibbs				       + sizeof(aha_mbox_out_t)),
56239225Sgibbs			ahamapmboxes, aha, /*flags*/0);
56339225Sgibbs
56439225Sgibbs	aha->init_level++;
56539225Sgibbs
56639225Sgibbs	aha->in_boxes = (aha_mbox_in_t *)&aha->out_boxes[aha->num_boxes];
56739225Sgibbs
56839225Sgibbs	ahainitmboxes(aha);
56939225Sgibbs
57039225Sgibbs	/* DMA tag for our ccb structures */
57139225Sgibbs	if (bus_dma_tag_create(aha->parent_dmat, /*alignment*/0, /*boundary*/0,
57239225Sgibbs			       /*lowaddr*/BUS_SPACE_MAXADDR,
57339225Sgibbs			       /*highaddr*/BUS_SPACE_MAXADDR,
57439225Sgibbs			       /*filter*/NULL, /*filterarg*/NULL,
57539225Sgibbs			       aha->max_ccbs * sizeof(struct aha_ccb),
57639225Sgibbs			       /*nsegments*/1,
57739225Sgibbs			       /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT,
57839225Sgibbs			       /*flags*/0, &aha->ccb_dmat) != 0) {
57939225Sgibbs		goto error_exit;
58039225Sgibbs        }
58139225Sgibbs
58239225Sgibbs	aha->init_level++;
58339225Sgibbs
58439225Sgibbs	/* Allocation for our ccbs */
58539225Sgibbs	if (bus_dmamem_alloc(aha->ccb_dmat, (void **)&aha->aha_ccb_array,
58639225Sgibbs			     BUS_DMA_NOWAIT, &aha->ccb_dmamap) != 0) {
58739225Sgibbs		goto error_exit;
58839225Sgibbs	}
58939225Sgibbs
59039225Sgibbs	aha->init_level++;
59139225Sgibbs
59239225Sgibbs	/* And permanently map them */
59339225Sgibbs	bus_dmamap_load(aha->ccb_dmat, aha->ccb_dmamap,
59439225Sgibbs       			aha->aha_ccb_array,
59539225Sgibbs			aha->max_ccbs * sizeof(struct aha_ccb),
59639225Sgibbs			ahamapccbs, aha, /*flags*/0);
59739225Sgibbs
59839225Sgibbs	aha->init_level++;
59939225Sgibbs
60039225Sgibbs	/* DMA tag for our S/G structures.  We allocate in page sized chunks */
60139225Sgibbs	if (bus_dma_tag_create(aha->parent_dmat, /*alignment*/0, /*boundary*/0,
60239225Sgibbs			       /*lowaddr*/BUS_SPACE_MAXADDR,
60339225Sgibbs			       /*highaddr*/BUS_SPACE_MAXADDR,
60439225Sgibbs			       /*filter*/NULL, /*filterarg*/NULL,
60539225Sgibbs			       PAGE_SIZE, /*nsegments*/1,
60639225Sgibbs			       /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT,
60739225Sgibbs			       /*flags*/0, &aha->sg_dmat) != 0) {
60839225Sgibbs		goto error_exit;
60939225Sgibbs        }
61039225Sgibbs
61139225Sgibbs	aha->init_level++;
61239225Sgibbs
61339225Sgibbs	/* Perform initial CCB allocation */
61439225Sgibbs	bzero(aha->aha_ccb_array, aha->max_ccbs * sizeof(struct aha_ccb));
61539225Sgibbs	ahaallocccbs(aha);
61639225Sgibbs
61739225Sgibbs	if (aha->num_ccbs == 0) {
61839324Sgibbs		printf("%s: aha_init - Unable to allocate initial ccbs\n",
61939324Sgibbs		       aha_name(aha));
62039225Sgibbs		goto error_exit;
62139225Sgibbs	}
62239225Sgibbs
62339225Sgibbs	/*
62439225Sgibbs	 * Note that we are going and return (to probe)
62539225Sgibbs	 */
62639225Sgibbs	return 0;
62739225Sgibbs
62839225Sgibbserror_exit:
62939225Sgibbs
63039225Sgibbs	return (ENXIO);
63139225Sgibbs}
63239225Sgibbs
63339225Sgibbsint
63439225Sgibbsaha_attach(struct aha_softc *aha)
63539225Sgibbs{
63639225Sgibbs	int tagged_dev_openings;
63739225Sgibbs	struct cam_devq *devq;
63839225Sgibbs
63939225Sgibbs	/*
64041335Simp	 * We don't do tagged queueing, since the aha cards don't
64141335Simp	 * support it.
64239225Sgibbs	 */
64339225Sgibbs	tagged_dev_openings = 0;
64439225Sgibbs
64539225Sgibbs	/*
64639225Sgibbs	 * Create the device queue for our SIM.
64739225Sgibbs	 */
64839225Sgibbs	devq = cam_simq_alloc(aha->max_ccbs - 1);
64939225Sgibbs	if (devq == NULL)
65039225Sgibbs		return (ENOMEM);
65139225Sgibbs
65239225Sgibbs	/*
65339225Sgibbs	 * Construct our SIM entry
65439225Sgibbs	 */
65539225Sgibbs	aha->sim = cam_sim_alloc(ahaaction, ahapoll, "aha", aha, aha->unit,
65639225Sgibbs				2, tagged_dev_openings, devq);
65739225Sgibbs	if (aha->sim == NULL) {
65839225Sgibbs		cam_simq_free(devq);
65939225Sgibbs		return (ENOMEM);
66039225Sgibbs	}
66139225Sgibbs
66239225Sgibbs	if (xpt_bus_register(aha->sim, 0) != CAM_SUCCESS) {
66339225Sgibbs		cam_sim_free(aha->sim, /*free_devq*/TRUE);
66439225Sgibbs		return (ENXIO);
66539225Sgibbs	}
66639225Sgibbs
66739225Sgibbs	if (xpt_create_path(&aha->path, /*periph*/NULL,
66839225Sgibbs			    cam_sim_path(aha->sim), CAM_TARGET_WILDCARD,
66939225Sgibbs			    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
67039225Sgibbs		xpt_bus_deregister(cam_sim_path(aha->sim));
67139225Sgibbs		cam_sim_free(aha->sim, /*free_devq*/TRUE);
67239225Sgibbs		return (ENXIO);
67339225Sgibbs	}
67439225Sgibbs
67539225Sgibbs	return (0);
67639225Sgibbs}
67739225Sgibbs
67839225Sgibbschar *
67939225Sgibbsaha_name(struct aha_softc *aha)
68039225Sgibbs{
68139225Sgibbs	static char name[10];
68239225Sgibbs
68341514Sarchie	snprintf(name, sizeof(name), "aha%d", aha->unit);
68439225Sgibbs	return (name);
68539225Sgibbs}
68639225Sgibbs
68739225Sgibbsint
68839225Sgibbsaha_check_probed_iop(u_int ioport)
68939225Sgibbs{
69039225Sgibbs	u_int i;
69139225Sgibbs
69239225Sgibbs	for (i=0; i < AHA_NUM_ISAPORTS; i++) {
69339225Sgibbs		if (aha_isa_ports[i].addr == ioport) {
69439225Sgibbs			if (aha_isa_ports[i].probed != 0)
69539225Sgibbs				return (1);
69639225Sgibbs			else {
69739225Sgibbs				return (0);
69839225Sgibbs			}
69939225Sgibbs		}
70039225Sgibbs	}
70139225Sgibbs	return (1);
70239225Sgibbs}
70339225Sgibbs
70439225Sgibbsvoid
70539225Sgibbsaha_mark_probed_bio(isa_compat_io_t port)
70639225Sgibbs{
70739225Sgibbs	if (port < BIO_DISABLED)
70841047Sgibbs		aha_mark_probed_iop(aha_board_ports[port]);
70939225Sgibbs}
71039225Sgibbs
71139225Sgibbsvoid
71239225Sgibbsaha_mark_probed_iop(u_int ioport)
71339225Sgibbs{
71439225Sgibbs	u_int i;
71539225Sgibbs
71639225Sgibbs	for (i = 0; i < AHA_NUM_ISAPORTS; i++) {
71739225Sgibbs		if (ioport == aha_isa_ports[i].addr) {
71839225Sgibbs			aha_isa_ports[i].probed = 1;
71939225Sgibbs			break;
72039225Sgibbs		}
72139225Sgibbs	}
72239225Sgibbs}
72339225Sgibbs
72441047Sgibbsvoid
72541047Sgibbsaha_find_probe_range(int ioport, int *port_index, int *max_port_index)
72641047Sgibbs{
72741047Sgibbs	if (ioport > 0) {
72841047Sgibbs		int i;
72941047Sgibbs
73041047Sgibbs		for (i = 0;i < AHA_NUM_ISAPORTS; i++)
73141047Sgibbs			if (ioport <= aha_isa_ports[i].addr)
73241047Sgibbs				break;
73341047Sgibbs		if ((i >= AHA_NUM_ISAPORTS)
73441047Sgibbs		 || (ioport != aha_isa_ports[i].addr)) {
73542013Sgibbs			printf("\n"
73642013Sgibbs"aha_isa_probe: Invalid baseport of 0x%x specified.\n"
73742013Sgibbs"aha_isa_probe: Nearest valid baseport is 0x%x.\n"
73842013Sgibbs"aha_isa_probe: Failing probe.\n",
73941047Sgibbs			       ioport,
74041047Sgibbs			       (i < AHA_NUM_ISAPORTS)
74141047Sgibbs				    ? aha_isa_ports[i].addr
74241047Sgibbs				    : aha_isa_ports[AHA_NUM_ISAPORTS - 1].addr);
74341047Sgibbs			*port_index = *max_port_index = -1;
74441047Sgibbs			return;
74541047Sgibbs		}
74641047Sgibbs		*port_index = *max_port_index = aha_isa_ports[i].bio;
74741047Sgibbs	} else {
74841047Sgibbs		*port_index = 0;
74941047Sgibbs		*max_port_index = AHA_NUM_ISAPORTS - 1;
75041047Sgibbs	}
75141047Sgibbs}
75241047Sgibbs
75341047Sgibbsint
75441047Sgibbsaha_iop_from_bio(isa_compat_io_t bio_index)
75541047Sgibbs{
75641047Sgibbs	if (bio_index >= 0 && bio_index < AHA_NUM_ISAPORTS)
75741047Sgibbs		return (aha_board_ports[bio_index]);
75841047Sgibbs	return (-1);
75941047Sgibbs}
76041047Sgibbs
76139225Sgibbsstatic void
76239225Sgibbsahaallocccbs(struct aha_softc *aha)
76339225Sgibbs{
76439225Sgibbs	struct aha_ccb *next_ccb;
76539225Sgibbs	struct sg_map_node *sg_map;
76639225Sgibbs	bus_addr_t physaddr;
76739225Sgibbs	aha_sg_t *segs;
76839225Sgibbs	int newcount;
76939225Sgibbs	int i;
77039225Sgibbs
77139225Sgibbs	next_ccb = &aha->aha_ccb_array[aha->num_ccbs];
77239225Sgibbs
77339225Sgibbs	sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT);
77439225Sgibbs
77539225Sgibbs	if (sg_map == NULL)
77639225Sgibbs		return;
77739225Sgibbs
77839225Sgibbs	/* Allocate S/G space for the next batch of CCBS */
77939225Sgibbs	if (bus_dmamem_alloc(aha->sg_dmat, (void **)&sg_map->sg_vaddr,
78039225Sgibbs			     BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) {
78139225Sgibbs		free(sg_map, M_DEVBUF);
78239225Sgibbs		return;
78339225Sgibbs	}
78439225Sgibbs
78539225Sgibbs	SLIST_INSERT_HEAD(&aha->sg_maps, sg_map, links);
78639225Sgibbs
78739225Sgibbs	bus_dmamap_load(aha->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr,
78839225Sgibbs			PAGE_SIZE, ahamapsgs, aha, /*flags*/0);
78939225Sgibbs
79039225Sgibbs	segs = sg_map->sg_vaddr;
79139225Sgibbs	physaddr = sg_map->sg_physaddr;
79239225Sgibbs
79339225Sgibbs	newcount = (PAGE_SIZE / (AHA_NSEG * sizeof(aha_sg_t)));
79439225Sgibbs	for (i = 0; aha->num_ccbs < aha->max_ccbs && i < newcount; i++) {
79539225Sgibbs		int error;
79639225Sgibbs
79739225Sgibbs		next_ccb->sg_list = segs;
79839225Sgibbs		next_ccb->sg_list_phys = physaddr;
79941047Sgibbs		next_ccb->flags = ACCB_FREE;
80039225Sgibbs		error = bus_dmamap_create(aha->buffer_dmat, /*flags*/0,
80139225Sgibbs					  &next_ccb->dmamap);
80239225Sgibbs		if (error != 0)
80339225Sgibbs			break;
80439225Sgibbs		SLIST_INSERT_HEAD(&aha->free_aha_ccbs, next_ccb, links);
80539225Sgibbs		segs += AHA_NSEG;
80639225Sgibbs		physaddr += (AHA_NSEG * sizeof(aha_sg_t));
80739225Sgibbs		next_ccb++;
80839225Sgibbs		aha->num_ccbs++;
80939225Sgibbs	}
81039225Sgibbs
81139225Sgibbs	/* Reserve a CCB for error recovery */
81241047Sgibbs	if (aha->recovery_accb == NULL) {
81341047Sgibbs		aha->recovery_accb = SLIST_FIRST(&aha->free_aha_ccbs);
81439225Sgibbs		SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links);
81539225Sgibbs	}
81639225Sgibbs}
81739225Sgibbs
81839225Sgibbsstatic __inline void
81941047Sgibbsahafreeccb(struct aha_softc *aha, struct aha_ccb *accb)
82039225Sgibbs{
82139225Sgibbs	int s;
82239225Sgibbs
82339225Sgibbs	s = splcam();
82441047Sgibbs	if ((accb->flags & ACCB_ACTIVE) != 0)
82541047Sgibbs		LIST_REMOVE(&accb->ccb->ccb_h, sim_links.le);
82639225Sgibbs	if (aha->resource_shortage != 0
82741047Sgibbs	 && (accb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) {
82841047Sgibbs		accb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
82939225Sgibbs		aha->resource_shortage = FALSE;
83039225Sgibbs	}
83141047Sgibbs	accb->flags = ACCB_FREE;
83241047Sgibbs	SLIST_INSERT_HEAD(&aha->free_aha_ccbs, accb, links);
83341047Sgibbs	aha->active_ccbs--;
83439225Sgibbs	splx(s);
83539225Sgibbs}
83639225Sgibbs
83739225Sgibbsstatic struct aha_ccb*
83839225Sgibbsahagetccb(struct aha_softc *aha)
83939225Sgibbs{
84041047Sgibbs	struct	aha_ccb* accb;
84139225Sgibbs	int	s;
84239225Sgibbs
84339225Sgibbs	s = splcam();
84441047Sgibbs	if ((accb = SLIST_FIRST(&aha->free_aha_ccbs)) != NULL) {
84539225Sgibbs		SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links);
84641047Sgibbs		aha->active_ccbs++;
84739225Sgibbs	} else if (aha->num_ccbs < aha->max_ccbs) {
84839225Sgibbs		ahaallocccbs(aha);
84941047Sgibbs		accb = SLIST_FIRST(&aha->free_aha_ccbs);
85041047Sgibbs		if (accb == NULL)
85141047Sgibbs			printf("%s: Can't malloc ACCB\n", aha_name(aha));
85241047Sgibbs		else {
85339225Sgibbs			SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links);
85441047Sgibbs			aha->active_ccbs++;
85541047Sgibbs		}
85639225Sgibbs	}
85739225Sgibbs	splx(s);
85839225Sgibbs
85941047Sgibbs	return (accb);
86039225Sgibbs}
86139225Sgibbs
86239225Sgibbsstatic void
86339225Sgibbsahaaction(struct cam_sim *sim, union ccb *ccb)
86439225Sgibbs{
86539225Sgibbs	struct	aha_softc *aha;
86639225Sgibbs
86739225Sgibbs	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahaaction\n"));
86839225Sgibbs
86939225Sgibbs	aha = (struct aha_softc *)cam_sim_softc(sim);
87039225Sgibbs
87139225Sgibbs	switch (ccb->ccb_h.func_code) {
87239225Sgibbs	/* Common cases first */
87339225Sgibbs	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
87439225Sgibbs	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
87539225Sgibbs	{
87641047Sgibbs		struct	aha_ccb	*accb;
87739225Sgibbs		struct	aha_hccb *hccb;
87839225Sgibbs
87939225Sgibbs		/*
88041047Sgibbs		 * get a accb to use.
88139225Sgibbs		 */
88241047Sgibbs		if ((accb = ahagetccb(aha)) == NULL) {
88339225Sgibbs			int s;
88439225Sgibbs
88539225Sgibbs			s = splcam();
88639225Sgibbs			aha->resource_shortage = TRUE;
88739225Sgibbs			splx(s);
88839225Sgibbs			xpt_freeze_simq(aha->sim, /*count*/1);
88939225Sgibbs			ccb->ccb_h.status = CAM_REQUEUE_REQ;
89039225Sgibbs			xpt_done(ccb);
89139225Sgibbs			return;
89239225Sgibbs		}
89339225Sgibbs
89441047Sgibbs		hccb = &accb->hccb;
89539225Sgibbs
89639225Sgibbs		/*
89741047Sgibbs		 * So we can find the ACCB when an abort is requested
89839225Sgibbs		 */
89941047Sgibbs		accb->ccb = ccb;
90041047Sgibbs		ccb->ccb_h.ccb_accb_ptr = accb;
90139225Sgibbs		ccb->ccb_h.ccb_aha_ptr = aha;
90239225Sgibbs
90339225Sgibbs		/*
90441047Sgibbs		 * Put all the arguments for the xfer in the accb
90539225Sgibbs		 */
90639225Sgibbs		hccb->target = ccb->ccb_h.target_id;
90739225Sgibbs		hccb->lun = ccb->ccb_h.target_lun;
90839225Sgibbs		hccb->ahastat = 0;
90939225Sgibbs		hccb->sdstat = 0;
91039225Sgibbs
91139225Sgibbs		if (ccb->ccb_h.func_code == XPT_SCSI_IO) {
91239225Sgibbs			struct ccb_scsiio *csio;
91339225Sgibbs			struct ccb_hdr *ccbh;
91439225Sgibbs
91539225Sgibbs			csio = &ccb->csio;
91639225Sgibbs			ccbh = &csio->ccb_h;
91742887Simp			hccb->opcode = aha->ccb_ccb_opcode;
91839225Sgibbs			hccb->datain = (ccb->ccb_h.flags & CAM_DIR_IN) != 0;
91939225Sgibbs			hccb->dataout = (ccb->ccb_h.flags & CAM_DIR_OUT) != 0;
92039225Sgibbs			hccb->cmd_len = csio->cdb_len;
92139225Sgibbs			if (hccb->cmd_len > sizeof(hccb->scsi_cdb)) {
92239225Sgibbs				ccb->ccb_h.status = CAM_REQ_INVALID;
92341047Sgibbs				ahafreeccb(aha, accb);
92439225Sgibbs				xpt_done(ccb);
92539225Sgibbs				return;
92639225Sgibbs			}
92739225Sgibbs			hccb->sense_len = csio->sense_len;
92839225Sgibbs			if ((ccbh->flags & CAM_CDB_POINTER) != 0) {
92939225Sgibbs				if ((ccbh->flags & CAM_CDB_PHYS) == 0) {
93039225Sgibbs					bcopy(csio->cdb_io.cdb_ptr,
93139225Sgibbs					      hccb->scsi_cdb, hccb->cmd_len);
93239225Sgibbs				} else {
93339225Sgibbs					/* I guess I could map it in... */
93439225Sgibbs					ccbh->status = CAM_REQ_INVALID;
93541047Sgibbs					ahafreeccb(aha, accb);
93639225Sgibbs					xpt_done(ccb);
93739225Sgibbs					return;
93839225Sgibbs				}
93939225Sgibbs			} else {
94039225Sgibbs				bcopy(csio->cdb_io.cdb_bytes,
94139225Sgibbs				      hccb->scsi_cdb, hccb->cmd_len);
94239225Sgibbs			}
94339225Sgibbs			/*
94439225Sgibbs			 * If we have any data to send with this command,
94539225Sgibbs			 * map it into bus space.
94639225Sgibbs			 */
94739225Sgibbs		        /* Only use S/G if there is a transfer */
94839225Sgibbs			if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
94939225Sgibbs				if ((ccbh->flags & CAM_SCATTER_VALID) == 0) {
95039225Sgibbs					/*
95139225Sgibbs					 * We've been given a pointer
95239225Sgibbs					 * to a single buffer.
95339225Sgibbs					 */
95439225Sgibbs					if ((ccbh->flags & CAM_DATA_PHYS)==0) {
95539225Sgibbs						int s;
95639225Sgibbs						int error;
95739225Sgibbs
95839225Sgibbs						s = splsoftvm();
95939225Sgibbs						error = bus_dmamap_load(
96039225Sgibbs						    aha->buffer_dmat,
96141047Sgibbs						    accb->dmamap,
96239225Sgibbs						    csio->data_ptr,
96339225Sgibbs						    csio->dxfer_len,
96439225Sgibbs						    ahaexecuteccb,
96541047Sgibbs						    accb,
96639225Sgibbs						    /*flags*/0);
96739225Sgibbs						if (error == EINPROGRESS) {
96839225Sgibbs							/*
96939225Sgibbs							 * So as to maintain
97039225Sgibbs							 * ordering, freeze the
97139225Sgibbs							 * controller queue
97239225Sgibbs							 * until our mapping is
97339225Sgibbs							 * returned.
97439225Sgibbs							 */
97539225Sgibbs							xpt_freeze_simq(aha->sim,
97639225Sgibbs									1);
97739225Sgibbs							csio->ccb_h.status |=
97839225Sgibbs							    CAM_RELEASE_SIMQ;
97939225Sgibbs						}
98039225Sgibbs						splx(s);
98139225Sgibbs					} else {
98239225Sgibbs						struct bus_dma_segment seg;
98339225Sgibbs
98439225Sgibbs						/* Pointer to physical buffer */
98539225Sgibbs						seg.ds_addr =
98639225Sgibbs						    (bus_addr_t)csio->data_ptr;
98739225Sgibbs						seg.ds_len = csio->dxfer_len;
98841047Sgibbs						ahaexecuteccb(accb, &seg, 1, 0);
98939225Sgibbs					}
99039225Sgibbs				} else {
99139225Sgibbs					struct bus_dma_segment *segs;
99239225Sgibbs
99339225Sgibbs					if ((ccbh->flags & CAM_DATA_PHYS) != 0)
99439225Sgibbs						panic("ahaaction - Physical "
99539225Sgibbs						      "segment pointers "
99639225Sgibbs						      "unsupported");
99739225Sgibbs
99839225Sgibbs					if ((ccbh->flags&CAM_SG_LIST_PHYS)==0)
99939225Sgibbs						panic("ahaaction - Virtual "
100039225Sgibbs						      "segment addresses "
100139225Sgibbs						      "unsupported");
100239225Sgibbs
100339225Sgibbs					/* Just use the segments provided */
100439225Sgibbs					segs = (struct bus_dma_segment *)
100539225Sgibbs					    csio->data_ptr;
100641047Sgibbs					ahaexecuteccb(accb, segs,
100739225Sgibbs						     csio->sglist_cnt, 0);
100839225Sgibbs				}
100939225Sgibbs			} else {
101041047Sgibbs				ahaexecuteccb(accb, NULL, 0, 0);
101139225Sgibbs			}
101239225Sgibbs		} else {
101339225Sgibbs			hccb->opcode = INITIATOR_BUS_DEV_RESET;
101439225Sgibbs			/* No data transfer */
101539225Sgibbs			hccb->datain = TRUE;
101639225Sgibbs			hccb->dataout = TRUE;
101739225Sgibbs			hccb->cmd_len = 0;
101839225Sgibbs			hccb->sense_len = 0;
101941047Sgibbs			ahaexecuteccb(accb, NULL, 0, 0);
102039225Sgibbs		}
102139225Sgibbs		break;
102239225Sgibbs	}
102339225Sgibbs	case XPT_EN_LUN:		/* Enable LUN as a target */
102439225Sgibbs	case XPT_TARGET_IO:		/* Execute target I/O request */
102539225Sgibbs	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
102639225Sgibbs	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/
102739225Sgibbs	case XPT_ABORT:			/* Abort the specified CCB */
102839225Sgibbs		/* XXX Implement */
102939225Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
103039225Sgibbs		xpt_done(ccb);
103139225Sgibbs		break;
103239225Sgibbs	case XPT_SET_TRAN_SETTINGS:
103339225Sgibbs	{
103439225Sgibbs		/* XXX Implement */
103546581Sken		ccb->ccb_h.status = CAM_PROVIDE_FAIL;
103639225Sgibbs		xpt_done(ccb);
103739225Sgibbs		break;
103839225Sgibbs	}
103939225Sgibbs	case XPT_GET_TRAN_SETTINGS:
104039225Sgibbs	/* Get default/user set transfer settings for the target */
104139225Sgibbs	{
104239225Sgibbs		struct	ccb_trans_settings *cts;
104339225Sgibbs		u_int	target_mask;
104439225Sgibbs
104539225Sgibbs		cts = &ccb->cts;
104639225Sgibbs		target_mask = 0x01 << ccb->ccb_h.target_id;
104739225Sgibbs		if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) {
104839225Sgibbs			cts->flags = 0;
104939225Sgibbs			if ((aha->disc_permitted & target_mask) != 0)
105039225Sgibbs				cts->flags |= CCB_TRANS_DISC_ENB;
105139225Sgibbs			cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
105239225Sgibbs			if ((aha->sync_permitted & target_mask) != 0)
105339225Sgibbs				cts->sync_period = 50;
105439225Sgibbs			else
105539225Sgibbs				cts->sync_period = 0;
105639225Sgibbs
105739225Sgibbs			if (cts->sync_period != 0)
105839225Sgibbs				cts->sync_offset = 15;
105939225Sgibbs
106039225Sgibbs			cts->valid = CCB_TRANS_SYNC_RATE_VALID
106139225Sgibbs				   | CCB_TRANS_SYNC_OFFSET_VALID
106239225Sgibbs				   | CCB_TRANS_BUS_WIDTH_VALID
106339225Sgibbs				   | CCB_TRANS_DISC_VALID
106439225Sgibbs				   | CCB_TRANS_TQ_VALID;
106539225Sgibbs		} else {
106639225Sgibbs			ahafetchtransinfo(aha, cts);
106739225Sgibbs		}
106839225Sgibbs
106939225Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
107039225Sgibbs		xpt_done(ccb);
107139225Sgibbs		break;
107239225Sgibbs	}
107339225Sgibbs	case XPT_CALC_GEOMETRY:
107439225Sgibbs	{
107539225Sgibbs		struct	  ccb_calc_geometry *ccg;
107639225Sgibbs		u_int32_t size_mb;
107739225Sgibbs		u_int32_t secs_per_cylinder;
107839225Sgibbs
107939225Sgibbs		ccg = &ccb->ccg;
108039225Sgibbs		size_mb = ccg->volume_size
108139225Sgibbs			/ ((1024L * 1024L) / ccg->block_size);
108239225Sgibbs
108339225Sgibbs		if (size_mb >= 1024 && (aha->extended_trans != 0)) {
108439225Sgibbs			if (size_mb >= 2048) {
108539225Sgibbs				ccg->heads = 255;
108639225Sgibbs				ccg->secs_per_track = 63;
108739225Sgibbs			} else {
108839225Sgibbs				ccg->heads = 128;
108939225Sgibbs				ccg->secs_per_track = 32;
109039225Sgibbs			}
109139225Sgibbs		} else {
109239225Sgibbs			ccg->heads = 64;
109339225Sgibbs			ccg->secs_per_track = 32;
109439225Sgibbs		}
109539225Sgibbs		secs_per_cylinder = ccg->heads * ccg->secs_per_track;
109639225Sgibbs		ccg->cylinders = ccg->volume_size / secs_per_cylinder;
109739225Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
109839225Sgibbs		xpt_done(ccb);
109939225Sgibbs		break;
110039225Sgibbs	}
110139225Sgibbs	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
110239225Sgibbs	{
110339225Sgibbs		ahareset(aha, /*hardreset*/TRUE);
110439225Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
110539225Sgibbs		xpt_done(ccb);
110639225Sgibbs		break;
110739225Sgibbs	}
110839225Sgibbs	case XPT_TERM_IO:		/* Terminate the I/O process */
110939225Sgibbs		/* XXX Implement */
111039225Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
111139225Sgibbs		xpt_done(ccb);
111239225Sgibbs		break;
111339225Sgibbs	case XPT_PATH_INQ:		/* Path routing inquiry */
111439225Sgibbs	{
111539225Sgibbs		struct ccb_pathinq *cpi = &ccb->cpi;
111639225Sgibbs
111739225Sgibbs		cpi->version_num = 1; /* XXX??? */
111839225Sgibbs		cpi->hba_inquiry = PI_SDTR_ABLE;
111939225Sgibbs		cpi->target_sprt = 0;
112039225Sgibbs		cpi->hba_misc = 0;
112139225Sgibbs		cpi->hba_eng_cnt = 0;
112239852Simp		cpi->max_target = 7;
112339225Sgibbs		cpi->max_lun = 7;
112439225Sgibbs		cpi->initiator_id = aha->scsi_id;
112539225Sgibbs		cpi->bus_id = cam_sim_bus(sim);
112646581Sken		cpi->base_transfer_speed = 3300;
112739225Sgibbs		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
112839225Sgibbs		strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN);
112939225Sgibbs		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
113039225Sgibbs		cpi->unit_number = cam_sim_unit(sim);
113139225Sgibbs		cpi->ccb_h.status = CAM_REQ_CMP;
113239225Sgibbs		xpt_done(ccb);
113339225Sgibbs		break;
113439225Sgibbs	}
113539225Sgibbs	default:
113639225Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
113739225Sgibbs		xpt_done(ccb);
113839225Sgibbs		break;
113939225Sgibbs	}
114039225Sgibbs}
114139225Sgibbs
114239225Sgibbsstatic void
114339225Sgibbsahaexecuteccb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
114439225Sgibbs{
114541047Sgibbs	struct	 aha_ccb *accb;
114639225Sgibbs	union	 ccb *ccb;
114739225Sgibbs	struct	 aha_softc *aha;
114840419Sgibbs	int	 s;
114939225Sgibbs	u_int32_t paddr;
115039225Sgibbs
115141047Sgibbs	accb = (struct aha_ccb *)arg;
115241047Sgibbs	ccb = accb->ccb;
115339225Sgibbs	aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr;
115439225Sgibbs
115539225Sgibbs	if (error != 0) {
115639225Sgibbs		if (error != EFBIG)
115739225Sgibbs			printf("%s: Unexepected error 0x%x returned from "
115839324Sgibbs			       "bus_dmamap_load\n", aha_name(aha), error);
115939225Sgibbs		if (ccb->ccb_h.status == CAM_REQ_INPROG) {
116039225Sgibbs			xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
116139225Sgibbs			ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN;
116239225Sgibbs		}
116341047Sgibbs		ahafreeccb(aha, accb);
116439225Sgibbs		xpt_done(ccb);
116539225Sgibbs		return;
116639225Sgibbs	}
116739225Sgibbs
116839225Sgibbs	if (nseg != 0) {
116939225Sgibbs		aha_sg_t *sg;
117039225Sgibbs		bus_dma_segment_t *end_seg;
117139225Sgibbs		bus_dmasync_op_t op;
117239225Sgibbs
117339225Sgibbs		end_seg = dm_segs + nseg;
117439225Sgibbs
117539225Sgibbs		/* Copy the segments into our SG list */
117641047Sgibbs		sg = accb->sg_list;
117739225Sgibbs		while (dm_segs < end_seg) {
117839225Sgibbs			ahautoa24(dm_segs->ds_len, sg->len);
117939225Sgibbs			ahautoa24(dm_segs->ds_addr, sg->addr);
118039225Sgibbs			sg++;
118139225Sgibbs			dm_segs++;
118239225Sgibbs		}
118339225Sgibbs
118439225Sgibbs		if (nseg > 1) {
118542887Simp			accb->hccb.opcode = aha->ccb_sg_opcode;
118639225Sgibbs			ahautoa24((sizeof(aha_sg_t) * nseg),
118741047Sgibbs				  accb->hccb.data_len);
118841047Sgibbs			ahautoa24(accb->sg_list_phys, accb->hccb.data_addr);
118939225Sgibbs		} else {
119041047Sgibbs			bcopy(accb->sg_list->len, accb->hccb.data_len, 3);
119141047Sgibbs			bcopy(accb->sg_list->addr, accb->hccb.data_addr, 3);
119239225Sgibbs		}
119339225Sgibbs
119439225Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
119539225Sgibbs			op = BUS_DMASYNC_PREREAD;
119639225Sgibbs		else
119739225Sgibbs			op = BUS_DMASYNC_PREWRITE;
119839225Sgibbs
119941047Sgibbs		bus_dmamap_sync(aha->buffer_dmat, accb->dmamap, op);
120039225Sgibbs
120139225Sgibbs	} else {
120241709Sgibbs		accb->hccb.opcode = INITIATOR_CCB;
120341047Sgibbs		ahautoa24(0, accb->hccb.data_len);
120441047Sgibbs		ahautoa24(0, accb->hccb.data_addr);
120539225Sgibbs	}
120639225Sgibbs
120739225Sgibbs	s = splcam();
120839225Sgibbs
120939225Sgibbs	/*
121039225Sgibbs	 * Last time we need to check if this CCB needs to
121139225Sgibbs	 * be aborted.
121239225Sgibbs	 */
121339225Sgibbs	if (ccb->ccb_h.status != CAM_REQ_INPROG) {
121439225Sgibbs		if (nseg != 0)
121541047Sgibbs			bus_dmamap_unload(aha->buffer_dmat, accb->dmamap);
121641047Sgibbs		ahafreeccb(aha, accb);
121739225Sgibbs		xpt_done(ccb);
121839225Sgibbs		splx(s);
121939225Sgibbs		return;
122039225Sgibbs	}
122139225Sgibbs
122241047Sgibbs	accb->flags = ACCB_ACTIVE;
122339225Sgibbs	ccb->ccb_h.status |= CAM_SIM_QUEUED;
122439225Sgibbs	LIST_INSERT_HEAD(&aha->pending_ccbs, &ccb->ccb_h, sim_links.le);
122539225Sgibbs
122639225Sgibbs	ccb->ccb_h.timeout_ch =
122741047Sgibbs	    timeout(ahatimeout, (caddr_t)accb,
122839225Sgibbs		    (ccb->ccb_h.timeout * hz) / 1000);
122939225Sgibbs
123039225Sgibbs	/* Tell the adapter about this command */
123141047Sgibbs	if (aha->cur_outbox->action_code != AMBO_FREE) {
123241047Sgibbs		/*
123341047Sgibbs		 * We should never encounter a busy mailbox.
123441047Sgibbs		 * If we do, warn the user, and treat it as
123541047Sgibbs		 * a resource shortage.  If the controller is
123641047Sgibbs		 * hung, one of the pending transactions will
123741047Sgibbs		 * timeout causing us to start recovery operations.
123841047Sgibbs		 */
123941047Sgibbs		printf("%s: Encountered busy mailbox with %d out of %d "
124041047Sgibbs		       "commands active!!!", aha_name(aha), aha->active_ccbs,
124141047Sgibbs		       aha->max_ccbs);
124241047Sgibbs		untimeout(ahatimeout, accb, ccb->ccb_h.timeout_ch);
124341047Sgibbs		if (nseg != 0)
124441047Sgibbs			bus_dmamap_unload(aha->buffer_dmat, accb->dmamap);
124541047Sgibbs		ahafreeccb(aha, accb);
124641047Sgibbs		aha->resource_shortage = TRUE;
124741047Sgibbs		xpt_freeze_simq(aha->sim, /*count*/1);
124841047Sgibbs		ccb->ccb_h.status = CAM_REQUEUE_REQ;
124941047Sgibbs		xpt_done(ccb);
125041047Sgibbs		return;
125141047Sgibbs	}
125241047Sgibbs	paddr = ahaccbvtop(aha, accb);
125339225Sgibbs	ahautoa24(paddr, aha->cur_outbox->ccb_addr);
125441047Sgibbs	aha->cur_outbox->action_code = AMBO_START;
125541047Sgibbs	aha_outb(aha, COMMAND_REG, AOP_START_MBOX);
125639225Sgibbs
125739225Sgibbs	ahanextoutbox(aha);
125839225Sgibbs	splx(s);
125939225Sgibbs}
126039225Sgibbs
126139225Sgibbsvoid
126239225Sgibbsaha_intr(void *arg)
126339225Sgibbs{
126439225Sgibbs	struct	aha_softc *aha;
126539225Sgibbs	u_int	intstat;
126639225Sgibbs
126739225Sgibbs	aha = (struct aha_softc *)arg;
126839225Sgibbs	while (((intstat = aha_inb(aha, INTSTAT_REG)) & INTR_PENDING) != 0) {
126939225Sgibbs		if ((intstat & CMD_COMPLETE) != 0) {
127039225Sgibbs			aha->latched_status = aha_inb(aha, STATUS_REG);
127139225Sgibbs			aha->command_cmp = TRUE;
127239225Sgibbs		}
127339225Sgibbs
127439225Sgibbs		aha_outb(aha, CONTROL_REG, RESET_INTR);
127539225Sgibbs
127639225Sgibbs		if ((intstat & IMB_LOADED) != 0) {
127741047Sgibbs			while (aha->cur_inbox->comp_code != AMBI_FREE) {
127839225Sgibbs				u_int32_t	paddr;
127939225Sgibbs				paddr = aha_a24tou(aha->cur_inbox->ccb_addr);
128039225Sgibbs				ahadone(aha,
128139225Sgibbs				       ahaccbptov(aha, paddr),
128239225Sgibbs				       aha->cur_inbox->comp_code);
128341047Sgibbs				aha->cur_inbox->comp_code = AMBI_FREE;
128439225Sgibbs				ahanextinbox(aha);
128539225Sgibbs			}
128639225Sgibbs		}
128739225Sgibbs
128839225Sgibbs		if ((intstat & SCSI_BUS_RESET) != 0) {
128939225Sgibbs			ahareset(aha, /*hardreset*/FALSE);
129039225Sgibbs		}
129139225Sgibbs	}
129239225Sgibbs}
129339225Sgibbs
129439225Sgibbsstatic void
129541047Sgibbsahadone(struct aha_softc *aha, struct aha_ccb *accb, aha_mbi_comp_code_t comp_code)
129639225Sgibbs{
129739225Sgibbs	union  ccb	  *ccb;
129839225Sgibbs	struct ccb_scsiio *csio;
129939225Sgibbs
130041047Sgibbs	ccb = accb->ccb;
130141047Sgibbs	csio = &accb->ccb->csio;
130239225Sgibbs
130341047Sgibbs	if ((accb->flags & ACCB_ACTIVE) == 0) {
130441047Sgibbs		printf("%s: ahadone - Attempt to free non-active ACCB %p\n",
130541047Sgibbs		       aha_name(aha), (void *)accb);
130639225Sgibbs		return;
130739225Sgibbs	}
130839225Sgibbs
130939225Sgibbs	if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
131039225Sgibbs		bus_dmasync_op_t op;
131139225Sgibbs
131239225Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
131339225Sgibbs			op = BUS_DMASYNC_POSTREAD;
131439225Sgibbs		else
131539225Sgibbs			op = BUS_DMASYNC_POSTWRITE;
131641047Sgibbs		bus_dmamap_sync(aha->buffer_dmat, accb->dmamap, op);
131741047Sgibbs		bus_dmamap_unload(aha->buffer_dmat, accb->dmamap);
131839225Sgibbs	}
131939225Sgibbs
132041047Sgibbs	if (accb == aha->recovery_accb) {
132139225Sgibbs		/*
132241047Sgibbs		 * The recovery ACCB does not have a CCB associated
132339225Sgibbs		 * with it, so short circuit the normal error handling.
132439225Sgibbs		 * We now traverse our list of pending CCBs and process
132539225Sgibbs		 * any that were terminated by the recovery CCBs action.
132639225Sgibbs		 * We also reinstate timeouts for all remaining, pending,
132739225Sgibbs		 * CCBs.
132839225Sgibbs		 */
132939225Sgibbs		struct cam_path *path;
133039225Sgibbs		struct ccb_hdr *ccb_h;
133139225Sgibbs		cam_status error;
133239225Sgibbs
133339225Sgibbs		/* Notify all clients that a BDR occured */
133439225Sgibbs		error = xpt_create_path(&path, /*periph*/NULL,
133539225Sgibbs					cam_sim_path(aha->sim),
133641047Sgibbs					accb->hccb.target,
133739225Sgibbs					CAM_LUN_WILDCARD);
133839225Sgibbs
133939225Sgibbs		if (error == CAM_REQ_CMP)
134039225Sgibbs			xpt_async(AC_SENT_BDR, path, NULL);
134139225Sgibbs
134239225Sgibbs		ccb_h = LIST_FIRST(&aha->pending_ccbs);
134339225Sgibbs		while (ccb_h != NULL) {
134441047Sgibbs			struct aha_ccb *pending_accb;
134539225Sgibbs
134641047Sgibbs			pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr;
134741047Sgibbs			if (pending_accb->hccb.target == accb->hccb.target) {
134841047Sgibbs				pending_accb->hccb.ahastat = AHASTAT_HA_BDR;
134939225Sgibbs				ccb_h = LIST_NEXT(ccb_h, sim_links.le);
135041047Sgibbs				ahadone(aha, pending_accb, AMBI_ERROR);
135139225Sgibbs			} else {
135239225Sgibbs				ccb_h->timeout_ch =
135341047Sgibbs				    timeout(ahatimeout, (caddr_t)pending_accb,
135439225Sgibbs					    (ccb_h->timeout * hz) / 1000);
135539225Sgibbs				ccb_h = LIST_NEXT(ccb_h, sim_links.le);
135639225Sgibbs			}
135739225Sgibbs		}
135839225Sgibbs		printf("%s: No longer in timeout\n", aha_name(aha));
135939225Sgibbs		return;
136039225Sgibbs	}
136139225Sgibbs
136241047Sgibbs	untimeout(ahatimeout, accb, ccb->ccb_h.timeout_ch);
136339225Sgibbs
136439225Sgibbs	switch (comp_code) {
136541047Sgibbs	case AMBI_FREE:
136639225Sgibbs		printf("%s: ahadone - CCB completed with free status!\n",
136739225Sgibbs		       aha_name(aha));
136839225Sgibbs		break;
136941047Sgibbs	case AMBI_NOT_FOUND:
137039225Sgibbs		printf("%s: ahadone - CCB Abort failed to find CCB\n",
137139225Sgibbs		       aha_name(aha));
137239225Sgibbs		break;
137341047Sgibbs	case AMBI_ABORT:
137441047Sgibbs	case AMBI_ERROR:
137539225Sgibbs		/* An error occured */
137642887Simp		if (accb->hccb.opcode < INITIATOR_CCB_WRESID)
137742887Simp			csio->resid = 0;
137842887Simp		else
137942887Simp			csio->resid = aha_a24tou(accb->hccb.data_len);
138041047Sgibbs		switch(accb->hccb.ahastat) {
138139225Sgibbs		case AHASTAT_DATARUN_ERROR:
138242013Sgibbs		{
138342013Sgibbs			if (csio->resid <= 0) {
138439225Sgibbs				csio->ccb_h.status = CAM_DATA_RUN_ERR;
138539225Sgibbs				break;
138639225Sgibbs			}
138739225Sgibbs			/* FALLTHROUGH */
138842013Sgibbs		}
138939225Sgibbs		case AHASTAT_NOERROR:
139041047Sgibbs			csio->scsi_status = accb->hccb.sdstat;
139139225Sgibbs			csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
139239225Sgibbs			switch(csio->scsi_status) {
139339225Sgibbs			case SCSI_STATUS_CHECK_COND:
139439225Sgibbs			case SCSI_STATUS_CMD_TERMINATED:
139539225Sgibbs				csio->ccb_h.status |= CAM_AUTOSNS_VALID;
139639225Sgibbs				/*
139739225Sgibbs				 * The aha writes the sense data at different
139839225Sgibbs				 * offsets based on the scsi cmd len
139939225Sgibbs				 */
140041047Sgibbs				bcopy((caddr_t) &accb->hccb.scsi_cdb +
140141047Sgibbs					accb->hccb.cmd_len,
140239225Sgibbs					(caddr_t) &csio->sense_data,
140341047Sgibbs					accb->hccb.sense_len);
140439225Sgibbs				break;
140539225Sgibbs			default:
140639225Sgibbs				break;
140739225Sgibbs			case SCSI_STATUS_OK:
140839225Sgibbs				csio->ccb_h.status = CAM_REQ_CMP;
140939225Sgibbs				break;
141039225Sgibbs			}
141139225Sgibbs			break;
141239225Sgibbs		case AHASTAT_SELTIMEOUT:
141339225Sgibbs			csio->ccb_h.status = CAM_SEL_TIMEOUT;
141439225Sgibbs			break;
141539225Sgibbs		case AHASTAT_UNEXPECTED_BUSFREE:
141639225Sgibbs			csio->ccb_h.status = CAM_UNEXP_BUSFREE;
141739225Sgibbs			break;
141839225Sgibbs		case AHASTAT_INVALID_PHASE:
141939225Sgibbs			csio->ccb_h.status = CAM_SEQUENCE_FAIL;
142039225Sgibbs			break;
142139225Sgibbs		case AHASTAT_INVALID_ACTION_CODE:
142239225Sgibbs			panic("%s: Inavlid Action code", aha_name(aha));
142339225Sgibbs			break;
142439225Sgibbs		case AHASTAT_INVALID_OPCODE:
142542887Simp			if (accb->hccb.opcode < INITIATOR_CCB_WRESID)
142642887Simp				panic("%s: Invalid CCB Opcode %x hccb = %p",
142742887Simp					aha_name(aha), accb->hccb.opcode,
142842887Simp					&accb->hccb);
142942887Simp			printf("%s: AHA-1540A detected, compensating\n",
143042887Simp				aha_name(aha));
143142887Simp			aha->ccb_sg_opcode = INITIATOR_SG_CCB;
143242887Simp			aha->ccb_ccb_opcode = INITIATOR_CCB;
143342887Simp			xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
143442887Simp			csio->ccb_h.status = CAM_REQUEUE_REQ;
143539225Sgibbs			break;
143639225Sgibbs		case AHASTAT_LINKED_CCB_LUN_MISMATCH:
143739225Sgibbs			/* We don't even support linked commands... */
143839225Sgibbs			panic("%s: Linked CCB Lun Mismatch", aha_name(aha));
143939225Sgibbs			break;
144039225Sgibbs		case AHASTAT_INVALID_CCB_OR_SG_PARAM:
144139225Sgibbs			panic("%s: Invalid CCB or SG list", aha_name(aha));
144239225Sgibbs			break;
144339225Sgibbs		case AHASTAT_HA_SCSI_BUS_RESET:
144439225Sgibbs			if ((csio->ccb_h.status & CAM_STATUS_MASK)
144542887Simp			    != CAM_CMD_TIMEOUT)
144639225Sgibbs				csio->ccb_h.status = CAM_SCSI_BUS_RESET;
144739225Sgibbs			break;
144839225Sgibbs		case AHASTAT_HA_BDR:
144941047Sgibbs			if ((accb->flags & ACCB_DEVICE_RESET) == 0)
145039225Sgibbs				csio->ccb_h.status = CAM_BDR_SENT;
145139225Sgibbs			else
145239225Sgibbs				csio->ccb_h.status = CAM_CMD_TIMEOUT;
145339225Sgibbs			break;
145439225Sgibbs		}
145539225Sgibbs		if (csio->ccb_h.status != CAM_REQ_CMP) {
145639225Sgibbs			xpt_freeze_devq(csio->ccb_h.path, /*count*/1);
145739225Sgibbs			csio->ccb_h.status |= CAM_DEV_QFRZN;
145839225Sgibbs		}
145941047Sgibbs		if ((accb->flags & ACCB_RELEASE_SIMQ) != 0)
146039225Sgibbs			ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
146141047Sgibbs		ahafreeccb(aha, accb);
146239225Sgibbs		xpt_done(ccb);
146339225Sgibbs		break;
146441047Sgibbs	case AMBI_OK:
146539225Sgibbs		/* All completed without incident */
146639225Sgibbs		/* XXX DO WE NEED TO COPY SENSE BYTES HERE???? XXX */
146742887Simp		/* I don't think so since it works???? */
146839225Sgibbs		ccb->ccb_h.status |= CAM_REQ_CMP;
146941047Sgibbs		if ((accb->flags & ACCB_RELEASE_SIMQ) != 0)
147039225Sgibbs			ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
147141047Sgibbs		ahafreeccb(aha, accb);
147239225Sgibbs		xpt_done(ccb);
147339225Sgibbs		break;
147439225Sgibbs	}
147539225Sgibbs}
147639225Sgibbs
147739225Sgibbsstatic int
147839225Sgibbsahareset(struct aha_softc* aha, int hard_reset)
147939225Sgibbs{
148039225Sgibbs	struct	 ccb_hdr *ccb_h;
148139225Sgibbs	u_int	 status;
148239225Sgibbs	u_int	 timeout;
148339225Sgibbs	u_int8_t reset_type;
148439225Sgibbs
148539225Sgibbs	if (hard_reset != 0)
148639225Sgibbs		reset_type = HARD_RESET;
148739225Sgibbs	else
148839225Sgibbs		reset_type = SOFT_RESET;
148939225Sgibbs	aha_outb(aha, CONTROL_REG, reset_type);
149039225Sgibbs
149139225Sgibbs	/* Wait 5sec. for Diagnostic start */
149239225Sgibbs	timeout = 5 * 10000;
149339225Sgibbs	while (--timeout) {
149439225Sgibbs		status = aha_inb(aha, STATUS_REG);
149539225Sgibbs		if ((status & DIAG_ACTIVE) != 0)
149639225Sgibbs			break;
149739225Sgibbs		DELAY(100);
149839225Sgibbs	}
149939225Sgibbs	if (timeout == 0) {
150039881Simp		PRVERB(("%s: ahareset - Diagnostic Active failed to "
150139881Simp			"assert. status = 0x%x\n", aha_name(aha),
150239881Simp			status));
150339225Sgibbs		return (ETIMEDOUT);
150439225Sgibbs	}
150539225Sgibbs
150639225Sgibbs	/* Wait 10sec. for Diagnostic end */
150739225Sgibbs	timeout = 10 * 10000;
150839225Sgibbs	while (--timeout) {
150939225Sgibbs		status = aha_inb(aha, STATUS_REG);
151039225Sgibbs		if ((status & DIAG_ACTIVE) == 0)
151139225Sgibbs			break;
151239225Sgibbs		DELAY(100);
151339225Sgibbs	}
151439225Sgibbs	if (timeout == 0) {
151539225Sgibbs		panic("%s: ahareset - Diagnostic Active failed to drop. "
151639225Sgibbs		       "status = 0x%x\n", aha_name(aha), status);
151739225Sgibbs		return (ETIMEDOUT);
151839225Sgibbs	}
151939225Sgibbs
152039225Sgibbs	/* Wait for the host adapter to become ready or report a failure */
152139225Sgibbs	timeout = 10000;
152239225Sgibbs	while (--timeout) {
152339225Sgibbs		status = aha_inb(aha, STATUS_REG);
152439225Sgibbs		if ((status & (DIAG_FAIL|HA_READY|DATAIN_REG_READY)) != 0)
152539225Sgibbs			break;
152639225Sgibbs		DELAY(100);
152739225Sgibbs	}
152839225Sgibbs	if (timeout == 0) {
152939225Sgibbs		printf("%s: ahareset - Host adapter failed to come ready. "
153039225Sgibbs		       "status = 0x%x\n", aha_name(aha), status);
153139225Sgibbs		return (ETIMEDOUT);
153239225Sgibbs	}
153339225Sgibbs
153439225Sgibbs	/* If the diagnostics failed, tell the user */
153539225Sgibbs	if ((status & DIAG_FAIL) != 0
153639225Sgibbs	 || (status & HA_READY) == 0) {
153739225Sgibbs		printf("%s: ahareset - Adapter failed diagnostics\n",
153839225Sgibbs		       aha_name(aha));
153939225Sgibbs
154039225Sgibbs		if ((status & DATAIN_REG_READY) != 0)
154139324Sgibbs			printf("%s: ahareset - Host Adapter Error "
154239324Sgibbs			       "code = 0x%x\n", aha_name(aha),
154339225Sgibbs			       aha_inb(aha, DATAIN_REG));
154439225Sgibbs		return (ENXIO);
154539225Sgibbs	}
154639225Sgibbs
154739225Sgibbs	/* If we've allocated mailboxes, initialize them */
154839225Sgibbs	if (aha->init_level > 4)
154939225Sgibbs		ahainitmboxes(aha);
155039225Sgibbs
155139225Sgibbs	/* If we've attached to the XPT, tell it about the event */
155239225Sgibbs	if (aha->path != NULL)
155339225Sgibbs		xpt_async(AC_BUS_RESET, aha->path, NULL);
155439225Sgibbs
155539225Sgibbs	/*
155639225Sgibbs	 * Perform completion processing for all outstanding CCBs.
155739225Sgibbs	 */
155839225Sgibbs	while ((ccb_h = LIST_FIRST(&aha->pending_ccbs)) != NULL) {
155941047Sgibbs		struct aha_ccb *pending_accb;
156039225Sgibbs
156141047Sgibbs		pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr;
156241047Sgibbs		pending_accb->hccb.ahastat = AHASTAT_HA_SCSI_BUS_RESET;
156341047Sgibbs		ahadone(aha, pending_accb, AMBI_ERROR);
156439225Sgibbs	}
156539225Sgibbs
156639225Sgibbs	return (0);
156739225Sgibbs}
156839225Sgibbs
156939225Sgibbs/*
157039225Sgibbs * Send a command to the adapter.
157139225Sgibbs */
157239225Sgibbsint
157339225Sgibbsaha_cmd(struct aha_softc *aha, aha_op_t opcode, u_int8_t *params,
157439225Sgibbs      u_int param_len, u_int8_t *reply_data, u_int reply_len,
157539225Sgibbs      u_int cmd_timeout)
157639225Sgibbs{
157739225Sgibbs	u_int	timeout;
157839225Sgibbs	u_int	status;
157939225Sgibbs	u_int	intstat;
158039225Sgibbs	u_int	reply_buf_size;
158139225Sgibbs	int	s;
158241709Sgibbs	int	cmd_complete;
158339225Sgibbs
158439225Sgibbs	/* No data returned to start */
158539225Sgibbs	reply_buf_size = reply_len;
158639225Sgibbs	reply_len = 0;
158739225Sgibbs	intstat = 0;
158841709Sgibbs	cmd_complete = 0;
158939225Sgibbs
159039225Sgibbs	aha->command_cmp = 0;
159139225Sgibbs	/*
159239225Sgibbs	 * Wait up to 1 sec. for the adapter to become
159339225Sgibbs	 * ready to accept commands.
159439225Sgibbs	 */
159539225Sgibbs	timeout = 10000;
159639225Sgibbs	while (--timeout) {
159739225Sgibbs
159839225Sgibbs		status = aha_inb(aha, STATUS_REG);
159939225Sgibbs		if ((status & HA_READY) != 0
160039225Sgibbs		 && (status & CMD_REG_BUSY) == 0)
160139225Sgibbs			break;
160239225Sgibbs		DELAY(100);
160339225Sgibbs	}
160439225Sgibbs	if (timeout == 0) {
160539225Sgibbs		printf("%s: aha_cmd: Timeout waiting for adapter ready, "
160639225Sgibbs		       "status = 0x%x\n", aha_name(aha), status);
160739225Sgibbs		return (ETIMEDOUT);
160839225Sgibbs	}
160939225Sgibbs
161039225Sgibbs	/*
161139225Sgibbs	 * Send the opcode followed by any necessary parameter bytes.
161239225Sgibbs	 */
161339225Sgibbs	aha_outb(aha, COMMAND_REG, opcode);
161439225Sgibbs
161539225Sgibbs	/*
161639225Sgibbs	 * Wait for up to 1sec to get the parameter list sent
161739225Sgibbs	 */
161839225Sgibbs	timeout = 10000;
161939225Sgibbs	while (param_len && --timeout) {
162039225Sgibbs		DELAY(100);
162139225Sgibbs		status = aha_inb(aha, STATUS_REG);
162239225Sgibbs		intstat = aha_inb(aha, INTSTAT_REG);
162339225Sgibbs		if ((intstat & (INTR_PENDING|CMD_COMPLETE))
162441709Sgibbs		 == (INTR_PENDING|CMD_COMPLETE)) {
162541709Sgibbs			cmd_complete = 1;
162639225Sgibbs			break;
162741709Sgibbs		}
162839225Sgibbs		if (aha->command_cmp != 0) {
162939225Sgibbs			status = aha->latched_status;
163041709Sgibbs			cmd_complete = 1;
163139225Sgibbs			break;
163239225Sgibbs		}
163339225Sgibbs		if ((status & DATAIN_REG_READY) != 0)
163439225Sgibbs			break;
163539225Sgibbs		if ((status & CMD_REG_BUSY) == 0) {
163639225Sgibbs			aha_outb(aha, COMMAND_REG, *params++);
163739225Sgibbs			param_len--;
163839225Sgibbs		}
163939225Sgibbs	}
164039225Sgibbs	if (timeout == 0) {
164139225Sgibbs		printf("%s: aha_cmd: Timeout sending parameters, "
164239225Sgibbs		       "status = 0x%x\n", aha_name(aha), status);
164339225Sgibbs		return (ETIMEDOUT);
164439225Sgibbs	}
164539225Sgibbs
164639225Sgibbs	/*
164739225Sgibbs	 * For all other commands, we wait for any output data
164839225Sgibbs	 * and the final comand completion interrupt.
164939225Sgibbs	 */
165041709Sgibbs	while (cmd_complete == 0 && --cmd_timeout) {
165139225Sgibbs
165239225Sgibbs		status = aha_inb(aha, STATUS_REG);
165339225Sgibbs		intstat = aha_inb(aha, INTSTAT_REG);
165439225Sgibbs		if ((intstat & (INTR_PENDING|CMD_COMPLETE))
165539225Sgibbs		 == (INTR_PENDING|CMD_COMPLETE))
165639225Sgibbs			break;
165739225Sgibbs
165839225Sgibbs		if (aha->command_cmp != 0) {
165939225Sgibbs			status = aha->latched_status;
166039225Sgibbs			break;
166139225Sgibbs		}
166239225Sgibbs
166339225Sgibbs		if ((status & DATAIN_REG_READY) != 0) {
166439225Sgibbs			u_int8_t data;
166539225Sgibbs
166639225Sgibbs			data = aha_inb(aha, DATAIN_REG);
166739225Sgibbs			if (reply_len < reply_buf_size) {
166839225Sgibbs				*reply_data++ = data;
166939225Sgibbs			} else {
167039225Sgibbs				printf("%s: aha_cmd - Discarded reply data byte "
167139225Sgibbs				       "for opcode 0x%x\n", aha_name(aha),
167239225Sgibbs				       opcode);
167339225Sgibbs			}
167439225Sgibbs			reply_len++;
167539225Sgibbs		}
167639225Sgibbs
167739225Sgibbs		DELAY(100);
167839225Sgibbs	}
167939225Sgibbs	if (timeout == 0) {
168039225Sgibbs		printf("%s: aha_cmd: Timeout waiting for reply data and "
168139225Sgibbs		       "command complete.\n%s: status = 0x%x, intstat = 0x%x, "
168239225Sgibbs		       "reply_len = %d\n", aha_name(aha), aha_name(aha), status,
168339225Sgibbs		       intstat, reply_len);
168439225Sgibbs		return (ETIMEDOUT);
168539225Sgibbs	}
168639225Sgibbs
168739225Sgibbs	/*
168839225Sgibbs	 * Clear any pending interrupts.  Block interrupts so our
168939225Sgibbs	 * interrupt handler is not re-entered.
169039225Sgibbs	 */
169139225Sgibbs	s = splcam();
169239225Sgibbs	aha_intr(aha);
169339225Sgibbs	splx(s);
169439225Sgibbs
169539225Sgibbs	/*
169639225Sgibbs	 * If the command was rejected by the controller, tell the caller.
169739225Sgibbs	 */
169839225Sgibbs	if ((status & CMD_INVALID) != 0) {
169939881Simp		PRVERB(("%s: Invalid Command 0x%x\n", aha_name(aha), opcode));
170039225Sgibbs		/*
170139225Sgibbs		 * Some early adapters may not recover properly from
170239225Sgibbs		 * an invalid command.  If it appears that the controller
170339225Sgibbs		 * has wedged (i.e. status was not cleared by our interrupt
170439225Sgibbs		 * reset above), perform a soft reset.
170539225Sgibbs      		 */
170639225Sgibbs		DELAY(1000);
170739225Sgibbs		status = aha_inb(aha, STATUS_REG);
170839225Sgibbs		if ((status & (CMD_INVALID|STATUS_REG_RSVD|DATAIN_REG_READY|
170939225Sgibbs			      CMD_REG_BUSY|DIAG_FAIL|DIAG_ACTIVE)) != 0
171039225Sgibbs		 || (status & (HA_READY|INIT_REQUIRED))
171139225Sgibbs		  != (HA_READY|INIT_REQUIRED)) {
171239852Simp			ahareset(aha, /*hard_reset*/FALSE);
171339225Sgibbs		}
171439225Sgibbs		return (EINVAL);
171539225Sgibbs	}
171639225Sgibbs
171739225Sgibbs
171839225Sgibbs	if (param_len > 0) {
171939225Sgibbs		/* The controller did not accept the full argument list */
172039225Sgibbs	 	return (E2BIG);
172139225Sgibbs	}
172239225Sgibbs
172339225Sgibbs	if (reply_len != reply_buf_size) {
172439225Sgibbs		/* Too much or too little data received */
172539225Sgibbs		return (EMSGSIZE);
172639225Sgibbs	}
172739225Sgibbs
172839225Sgibbs	/* We were successful */
172939225Sgibbs	return (0);
173039225Sgibbs}
173139225Sgibbs
173239225Sgibbsstatic int
173339225Sgibbsahainitmboxes(struct aha_softc *aha)
173439225Sgibbs{
173539225Sgibbs	int error;
173639225Sgibbs	init_24b_mbox_params_t init_mbox;
173739225Sgibbs
173839225Sgibbs	bzero(aha->in_boxes, sizeof(aha_mbox_in_t) * aha->num_boxes);
173939225Sgibbs	bzero(aha->out_boxes, sizeof(aha_mbox_out_t) * aha->num_boxes);
174039225Sgibbs	aha->cur_inbox = aha->in_boxes;
174139225Sgibbs	aha->last_inbox = aha->in_boxes + aha->num_boxes - 1;
174239225Sgibbs	aha->cur_outbox = aha->out_boxes;
174339225Sgibbs	aha->last_outbox = aha->out_boxes + aha->num_boxes - 1;
174439225Sgibbs
174539225Sgibbs	/* Tell the adapter about them */
174639225Sgibbs	init_mbox.num_mboxes = aha->num_boxes;
174739225Sgibbs	ahautoa24(aha->mailbox_physbase, init_mbox.base_addr);
174841047Sgibbs	error = aha_cmd(aha, AOP_INITIALIZE_MBOX, (u_int8_t *)&init_mbox,
174939225Sgibbs		       /*parmlen*/sizeof(init_mbox), /*reply_buf*/NULL,
175039225Sgibbs		       /*reply_len*/0, DEFAULT_CMD_TIMEOUT);
175139225Sgibbs
175239225Sgibbs	if (error != 0)
175339225Sgibbs		printf("ahainitmboxes: Initialization command failed\n");
175439225Sgibbs	return (error);
175539225Sgibbs}
175639225Sgibbs
175739225Sgibbs/*
175839225Sgibbs * Update the XPT's idea of the negotiated transfer
175939225Sgibbs * parameters for a particular target.
176039225Sgibbs */
176139225Sgibbsstatic void
176239225Sgibbsahafetchtransinfo(struct aha_softc *aha, struct ccb_trans_settings* cts)
176339225Sgibbs{
176439225Sgibbs	setup_data_t	setup_info;
176539225Sgibbs	u_int		target;
176639225Sgibbs	u_int		targ_offset;
176739225Sgibbs	u_int		sync_period;
176839225Sgibbs	int		error;
176939225Sgibbs	u_int8_t	param;
177039225Sgibbs	targ_syncinfo_t	sync_info;
177139225Sgibbs
177239225Sgibbs	target = cts->ccb_h.target_id;
177339225Sgibbs	targ_offset = (target & 0x7);
177439225Sgibbs
177539225Sgibbs	/*
177647208Simp	 * Inquire Setup Information.  This command retreives
177747208Simp	 * the sync info for older models.  We put a small delay here
177847208Simp	 * because that seems to help the stability.  10mS is known
177947208Simp	 * to work, but other values might also work.
178039225Sgibbs	 */
178147208Simp	DELAY(10000);
178239225Sgibbs	param = sizeof(setup_info);
178341047Sgibbs	error = aha_cmd(aha, AOP_INQUIRE_SETUP_INFO, &param, /*paramlen*/1,
178439225Sgibbs		       (u_int8_t*)&setup_info, sizeof(setup_info),
178539225Sgibbs		       DEFAULT_CMD_TIMEOUT);
178639225Sgibbs
178739225Sgibbs	if (error != 0) {
178839225Sgibbs		printf("%s: ahafetchtransinfo - Inquire Setup Info Failed\n",
178939225Sgibbs		       aha_name(aha));
179039225Sgibbs		return;
179139225Sgibbs	}
179239225Sgibbs
179339225Sgibbs	sync_info = setup_info.syncinfo[targ_offset];
179439225Sgibbs
179539225Sgibbs	if (sync_info.sync == 0)
179639225Sgibbs		cts->sync_offset = 0;
179739225Sgibbs	else
179839225Sgibbs		cts->sync_offset = sync_info.offset;
179939225Sgibbs
180039225Sgibbs	cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
180139225Sgibbs
180239225Sgibbs	sync_period = 2000 + (500 * sync_info.period);
180339225Sgibbs
180439225Sgibbs	/* Convert ns value to standard SCSI sync rate */
180539225Sgibbs	if (cts->sync_offset != 0)
180639225Sgibbs		cts->sync_period = scsi_calc_syncparam(sync_period);
180739225Sgibbs	else
180839225Sgibbs		cts->sync_period = 0;
180939225Sgibbs
181039225Sgibbs	cts->valid = CCB_TRANS_SYNC_RATE_VALID
181139225Sgibbs		   | CCB_TRANS_SYNC_OFFSET_VALID
181239225Sgibbs		   | CCB_TRANS_BUS_WIDTH_VALID;
181339225Sgibbs        xpt_async(AC_TRANSFER_NEG, cts->ccb_h.path, cts);
181439225Sgibbs}
181539225Sgibbs
181639225Sgibbsstatic void
181739225Sgibbsahamapmboxes(void *arg, bus_dma_segment_t *segs, int nseg, int error)
181839225Sgibbs{
181939225Sgibbs	struct aha_softc* aha;
182039225Sgibbs
182139225Sgibbs	aha = (struct aha_softc*)arg;
182239225Sgibbs	aha->mailbox_physbase = segs->ds_addr;
182339225Sgibbs}
182439225Sgibbs
182539225Sgibbsstatic void
182639225Sgibbsahamapccbs(void *arg, bus_dma_segment_t *segs, int nseg, int error)
182739225Sgibbs{
182839225Sgibbs	struct aha_softc* aha;
182939225Sgibbs
183039225Sgibbs	aha = (struct aha_softc*)arg;
183139225Sgibbs	aha->aha_ccb_physbase = segs->ds_addr;
183239225Sgibbs}
183339225Sgibbs
183439225Sgibbsstatic void
183539225Sgibbsahamapsgs(void *arg, bus_dma_segment_t *segs, int nseg, int error)
183639225Sgibbs{
183739225Sgibbs
183839225Sgibbs	struct aha_softc* aha;
183939225Sgibbs
184039225Sgibbs	aha = (struct aha_softc*)arg;
184139225Sgibbs	SLIST_FIRST(&aha->sg_maps)->sg_physaddr = segs->ds_addr;
184239225Sgibbs}
184339225Sgibbs
184439225Sgibbsstatic void
184539225Sgibbsahapoll(struct cam_sim *sim)
184639225Sgibbs{
184740132Sgibbs	aha_intr(cam_sim_softc(sim));
184839225Sgibbs}
184939225Sgibbs
185045575Seivindstatic void
185139225Sgibbsahatimeout(void *arg)
185239225Sgibbs{
185341047Sgibbs	struct aha_ccb	*accb;
185439225Sgibbs	union  ccb	*ccb;
185539225Sgibbs	struct aha_softc *aha;
185639225Sgibbs	int		 s;
185739225Sgibbs	u_int32_t	paddr;
185839225Sgibbs
185941047Sgibbs	accb = (struct aha_ccb *)arg;
186041047Sgibbs	ccb = accb->ccb;
186139225Sgibbs	aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr;
186239225Sgibbs	xpt_print_path(ccb->ccb_h.path);
186341047Sgibbs	printf("CCB %p - timed out\n", (void *)accb);
186439225Sgibbs
186539225Sgibbs	s = splcam();
186639225Sgibbs
186741047Sgibbs	if ((accb->flags & ACCB_ACTIVE) == 0) {
186839225Sgibbs		xpt_print_path(ccb->ccb_h.path);
186939390Sgibbs		printf("CCB %p - timed out CCB already completed\n",
187041047Sgibbs		       (void *)accb);
187139225Sgibbs		splx(s);
187239225Sgibbs		return;
187339225Sgibbs	}
187439225Sgibbs
187539225Sgibbs	/*
187639225Sgibbs	 * In order to simplify the recovery process, we ask the XPT
187739225Sgibbs	 * layer to halt the queue of new transactions and we traverse
187839225Sgibbs	 * the list of pending CCBs and remove their timeouts. This
187939225Sgibbs	 * means that the driver attempts to clear only one error
188039225Sgibbs	 * condition at a time.  In general, timeouts that occur
188139225Sgibbs	 * close together are related anyway, so there is no benefit
188239225Sgibbs	 * in attempting to handle errors in parrallel.  Timeouts will
188339225Sgibbs	 * be reinstated when the recovery process ends.
188439225Sgibbs	 */
188541047Sgibbs	if ((accb->flags & ACCB_DEVICE_RESET) == 0) {
188639225Sgibbs		struct ccb_hdr *ccb_h;
188739225Sgibbs
188841047Sgibbs		if ((accb->flags & ACCB_RELEASE_SIMQ) == 0) {
188939225Sgibbs			xpt_freeze_simq(aha->sim, /*count*/1);
189041047Sgibbs			accb->flags |= ACCB_RELEASE_SIMQ;
189139225Sgibbs		}
189239225Sgibbs
189339225Sgibbs		ccb_h = LIST_FIRST(&aha->pending_ccbs);
189439225Sgibbs		while (ccb_h != NULL) {
189541047Sgibbs			struct aha_ccb *pending_accb;
189639225Sgibbs
189741047Sgibbs			pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr;
189841047Sgibbs			untimeout(ahatimeout, pending_accb, ccb_h->timeout_ch);
189939225Sgibbs			ccb_h = LIST_NEXT(ccb_h, sim_links.le);
190039225Sgibbs		}
190139225Sgibbs	}
190239225Sgibbs
190341047Sgibbs	if ((accb->flags & ACCB_DEVICE_RESET) != 0
190441047Sgibbs	 || aha->cur_outbox->action_code != AMBO_FREE) {
190539225Sgibbs		/*
190639225Sgibbs		 * Try a full host adapter/SCSI bus reset.
190739225Sgibbs		 * We do this only if we have already attempted
190839225Sgibbs		 * to clear the condition with a BDR, or we cannot
190939225Sgibbs		 * attempt a BDR for lack of mailbox resources.
191039225Sgibbs		 */
191139225Sgibbs		ccb->ccb_h.status = CAM_CMD_TIMEOUT;
191239225Sgibbs		ahareset(aha, /*hardreset*/TRUE);
191339225Sgibbs		printf("%s: No longer in timeout\n", aha_name(aha));
191439225Sgibbs	} else {
191539225Sgibbs		/*
191639225Sgibbs		 * Send a Bus Device Reset message:
191739225Sgibbs		 * The target that is holding up the bus may not
191839225Sgibbs		 * be the same as the one that triggered this timeout
191939225Sgibbs		 * (different commands have different timeout lengths),
192039225Sgibbs		 * but we have no way of determining this from our
192139225Sgibbs		 * timeout handler.  Our strategy here is to queue a
192239225Sgibbs		 * BDR message to the target of the timed out command.
192339225Sgibbs		 * If this fails, we'll get another timeout 2 seconds
192439225Sgibbs		 * later which will attempt a bus reset.
192539225Sgibbs		 */
192641047Sgibbs		accb->flags |= ACCB_DEVICE_RESET;
192741047Sgibbs		ccb->ccb_h.timeout_ch = timeout(ahatimeout, (caddr_t)accb, 2 * hz);
192841047Sgibbs		aha->recovery_accb->hccb.opcode = INITIATOR_BUS_DEV_RESET;
192939225Sgibbs
193039225Sgibbs		/* No Data Transfer */
193141047Sgibbs		aha->recovery_accb->hccb.datain = TRUE;
193241047Sgibbs		aha->recovery_accb->hccb.dataout = TRUE;
193341047Sgibbs		aha->recovery_accb->hccb.ahastat = 0;
193441047Sgibbs		aha->recovery_accb->hccb.sdstat = 0;
193541047Sgibbs		aha->recovery_accb->hccb.target = ccb->ccb_h.target_id;
193639225Sgibbs
193739225Sgibbs		/* Tell the adapter about this command */
193841047Sgibbs		paddr = ahaccbvtop(aha, aha->recovery_accb);
193939225Sgibbs		ahautoa24(paddr, aha->cur_outbox->ccb_addr);
194041047Sgibbs		aha->cur_outbox->action_code = AMBO_START;
194141047Sgibbs		aha_outb(aha, COMMAND_REG, AOP_START_MBOX);
194239225Sgibbs		ahanextoutbox(aha);
194339225Sgibbs	}
194439225Sgibbs
194539225Sgibbs	splx(s);
194639225Sgibbs}
1947