aha.c revision 47506
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 *
5847506Sgibbs *      $Id: aha.c,v 1.25 1999/05/14 23:10:25 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
10347506Sgibbs#ifndef MAX
10447506Sgibbs#define MAX(a, b) ((a) > (b) ? (a) : (b))
10547506Sgibbs#endif
10647506Sgibbs
10739225Sgibbs/* MailBox Management functions */
10839225Sgibbsstatic __inline void	ahanextinbox(struct aha_softc *aha);
10939225Sgibbsstatic __inline void	ahanextoutbox(struct aha_softc *aha);
11039225Sgibbs
11139225Sgibbsstatic __inline void
11239225Sgibbsahanextinbox(struct aha_softc *aha)
11339225Sgibbs{
11439225Sgibbs	if (aha->cur_inbox == aha->last_inbox)
11539225Sgibbs		aha->cur_inbox = aha->in_boxes;
11639225Sgibbs	else
11739225Sgibbs		aha->cur_inbox++;
11839225Sgibbs}
11939225Sgibbs
12039225Sgibbsstatic __inline void
12139225Sgibbsahanextoutbox(struct aha_softc *aha)
12239225Sgibbs{
12339225Sgibbs	if (aha->cur_outbox == aha->last_outbox)
12439225Sgibbs		aha->cur_outbox = aha->out_boxes;
12539225Sgibbs	else
12639225Sgibbs		aha->cur_outbox++;
12739225Sgibbs}
12839225Sgibbs
12939225Sgibbs#define ahautoa24(u,s3)			\
13039225Sgibbs	(s3)[0] = ((u) >> 16) & 0xff;	\
13139225Sgibbs	(s3)[1] = ((u) >> 8) & 0xff;	\
13239225Sgibbs	(s3)[2] = (u) & 0xff;
13339225Sgibbs
13439225Sgibbs#define aha_a24tou(s3) \
13539225Sgibbs	(((s3)[0] << 16) | ((s3)[1] << 8) | (s3)[2])
13639225Sgibbs
13739225Sgibbs/* CCB Mangement functions */
13839225Sgibbsstatic __inline u_int32_t		ahaccbvtop(struct aha_softc *aha,
13941047Sgibbs						  struct aha_ccb *accb);
14039225Sgibbsstatic __inline struct aha_ccb*		ahaccbptov(struct aha_softc *aha,
14139225Sgibbs						  u_int32_t ccb_addr);
14239225Sgibbs
14339225Sgibbsstatic __inline u_int32_t
14441047Sgibbsahaccbvtop(struct aha_softc *aha, struct aha_ccb *accb)
14539225Sgibbs{
14639225Sgibbs	return (aha->aha_ccb_physbase
14741047Sgibbs	      + (u_int32_t)((caddr_t)accb - (caddr_t)aha->aha_ccb_array));
14839225Sgibbs}
14939225Sgibbsstatic __inline struct aha_ccb *
15039225Sgibbsahaccbptov(struct aha_softc *aha, u_int32_t ccb_addr)
15139225Sgibbs{
15239225Sgibbs	return (aha->aha_ccb_array +
15339225Sgibbs	      + ((struct aha_ccb*)ccb_addr-(struct aha_ccb*)aha->aha_ccb_physbase));
15439225Sgibbs}
15539225Sgibbs
15639225Sgibbsstatic struct aha_ccb*	ahagetccb(struct aha_softc *aha);
15741047Sgibbsstatic __inline void	ahafreeccb(struct aha_softc *aha, struct aha_ccb *accb);
15839225Sgibbsstatic void		ahaallocccbs(struct aha_softc *aha);
15939225Sgibbsstatic bus_dmamap_callback_t ahaexecuteccb;
16041047Sgibbsstatic void		ahadone(struct aha_softc *aha, struct aha_ccb *accb,
16139225Sgibbs			       aha_mbi_comp_code_t comp_code);
16239225Sgibbs
16339225Sgibbs/* Host adapter command functions */
16439225Sgibbsstatic int	ahareset(struct aha_softc* aha, int hard_reset);
16539225Sgibbs
16639225Sgibbs/* Initialization functions */
16739225Sgibbsstatic int			ahainitmboxes(struct aha_softc *aha);
16839225Sgibbsstatic bus_dmamap_callback_t	ahamapmboxes;
16939225Sgibbsstatic bus_dmamap_callback_t	ahamapccbs;
17039225Sgibbsstatic bus_dmamap_callback_t	ahamapsgs;
17139225Sgibbs
17239225Sgibbs/* Transfer Negotiation Functions */
17339225Sgibbsstatic void ahafetchtransinfo(struct aha_softc *aha,
17439225Sgibbs			     struct ccb_trans_settings *cts);
17539225Sgibbs
17639225Sgibbs/* CAM SIM entry points */
17741047Sgibbs#define ccb_accb_ptr spriv_ptr0
17839225Sgibbs#define ccb_aha_ptr spriv_ptr1
17939225Sgibbsstatic void	ahaaction(struct cam_sim *sim, union ccb *ccb);
18039225Sgibbsstatic void	ahapoll(struct cam_sim *sim);
18139225Sgibbs
18239225Sgibbs/* Our timeout handler */
18346602Speterstatic timeout_t ahatimeout;
18439225Sgibbs
18539225Sgibbsu_long aha_unit = 0;
18639225Sgibbs
18739225Sgibbs/*
18839225Sgibbs * Do our own re-probe protection until a configuration
18939225Sgibbs * manager can do it for us.  This ensures that we don't
19039225Sgibbs * reprobe a card already found by the EISA or PCI probes.
19139225Sgibbs */
19245575Seivindstatic struct aha_isa_port aha_isa_ports[] =
19339225Sgibbs{
19441047Sgibbs	{ 0x130, 0, 4 },
19541047Sgibbs	{ 0x134, 0, 5 },
19641047Sgibbs	{ 0x230, 0, 2 },
19741047Sgibbs	{ 0x234, 0, 3 },
19841047Sgibbs	{ 0x330, 0, 0 },
19941047Sgibbs	{ 0x334, 0, 1 }
20039225Sgibbs};
20139225Sgibbs
20241047Sgibbs/*
20341047Sgibbs * I/O ports listed in the order enumerated by the
20441047Sgibbs * card for certain op codes.
20541047Sgibbs */
20645575Seivindstatic u_int16_t aha_board_ports[] =
20741047Sgibbs{
20841047Sgibbs	0x330,
20941047Sgibbs	0x334,
21041047Sgibbs	0x230,
21141047Sgibbs	0x234,
21241047Sgibbs	0x130,
21341047Sgibbs	0x134
21441047Sgibbs};
21541047Sgibbs
21639225Sgibbs/* Exported functions */
21739225Sgibbsstruct aha_softc *
21839225Sgibbsaha_alloc(int unit, bus_space_tag_t tag, bus_space_handle_t bsh)
21939225Sgibbs{
22039225Sgibbs	struct  aha_softc *aha;
22139225Sgibbs
22239225Sgibbs	if (unit != AHA_TEMP_UNIT) {
22342887Simp		if (unit >= NAHATOT) {
22439225Sgibbs			printf("aha: unit number (%d) too high\n", unit);
22539225Sgibbs			return NULL;
22639225Sgibbs		}
22739225Sgibbs
22839225Sgibbs		/*
22939225Sgibbs		 * Allocate a storage area for us
23039225Sgibbs		 */
23139225Sgibbs		if (aha_softcs[unit]) {
23239225Sgibbs			printf("aha%d: memory already allocated\n", unit);
23339225Sgibbs			return NULL;
23439225Sgibbs		}
23539225Sgibbs	}
23639225Sgibbs
23739225Sgibbs	aha = malloc(sizeof(struct aha_softc), M_DEVBUF, M_NOWAIT);
23839225Sgibbs	if (!aha) {
23939225Sgibbs		printf("aha%d: cannot malloc!\n", unit);
24039225Sgibbs		return NULL;
24139225Sgibbs	}
24239225Sgibbs	bzero(aha, sizeof(struct aha_softc));
24339225Sgibbs	SLIST_INIT(&aha->free_aha_ccbs);
24439225Sgibbs	LIST_INIT(&aha->pending_ccbs);
24539225Sgibbs	SLIST_INIT(&aha->sg_maps);
24639225Sgibbs	aha->unit = unit;
24739225Sgibbs	aha->tag = tag;
24839225Sgibbs	aha->bsh = bsh;
24942887Simp	aha->ccb_sg_opcode = INITIATOR_SG_CCB_WRESID;
25042887Simp	aha->ccb_ccb_opcode = INITIATOR_CCB_WRESID;
25139225Sgibbs
25239225Sgibbs	if (aha->unit != AHA_TEMP_UNIT) {
25339225Sgibbs		aha_softcs[unit] = aha;
25439225Sgibbs	}
25539225Sgibbs	return (aha);
25639225Sgibbs}
25739225Sgibbs
25839225Sgibbsvoid
25939225Sgibbsaha_free(struct aha_softc *aha)
26039225Sgibbs{
26139225Sgibbs	switch (aha->init_level) {
26239225Sgibbs	default:
26339225Sgibbs	case 8:
26439225Sgibbs	{
26539225Sgibbs		struct sg_map_node *sg_map;
26639225Sgibbs
26739225Sgibbs		while ((sg_map = SLIST_FIRST(&aha->sg_maps))!= NULL) {
26839225Sgibbs			SLIST_REMOVE_HEAD(&aha->sg_maps, links);
26939225Sgibbs			bus_dmamap_unload(aha->sg_dmat,
27039225Sgibbs					  sg_map->sg_dmamap);
27139225Sgibbs			bus_dmamem_free(aha->sg_dmat, sg_map->sg_vaddr,
27239225Sgibbs					sg_map->sg_dmamap);
27339225Sgibbs			free(sg_map, M_DEVBUF);
27439225Sgibbs		}
27539225Sgibbs		bus_dma_tag_destroy(aha->sg_dmat);
27639225Sgibbs	}
27739225Sgibbs	case 7:
27839225Sgibbs		bus_dmamap_unload(aha->ccb_dmat, aha->ccb_dmamap);
27939225Sgibbs	case 6:
28039225Sgibbs		bus_dmamap_destroy(aha->ccb_dmat, aha->ccb_dmamap);
28139225Sgibbs		bus_dmamem_free(aha->ccb_dmat, aha->aha_ccb_array,
28239225Sgibbs				aha->ccb_dmamap);
28339225Sgibbs	case 5:
28439225Sgibbs		bus_dma_tag_destroy(aha->ccb_dmat);
28539225Sgibbs	case 4:
28639225Sgibbs		bus_dmamap_unload(aha->mailbox_dmat, aha->mailbox_dmamap);
28739225Sgibbs	case 3:
28839225Sgibbs		bus_dmamem_free(aha->mailbox_dmat, aha->in_boxes,
28939225Sgibbs				aha->mailbox_dmamap);
29039225Sgibbs		bus_dmamap_destroy(aha->mailbox_dmat, aha->mailbox_dmamap);
29139225Sgibbs	case 2:
29239225Sgibbs		bus_dma_tag_destroy(aha->buffer_dmat);
29339225Sgibbs	case 1:
29439225Sgibbs		bus_dma_tag_destroy(aha->mailbox_dmat);
29539225Sgibbs	case 0:
29639225Sgibbs	}
29739225Sgibbs	if (aha->unit != AHA_TEMP_UNIT) {
29839225Sgibbs		aha_softcs[aha->unit] = NULL;
29939225Sgibbs	}
30039225Sgibbs	free(aha, M_DEVBUF);
30139225Sgibbs}
30239225Sgibbs
30339225Sgibbs/*
30439225Sgibbs * Probe the adapter and verify that the card is an Adaptec.
30539225Sgibbs */
30639225Sgibbsint
30739225Sgibbsaha_probe(struct aha_softc* aha)
30839225Sgibbs{
30939225Sgibbs	u_int	 status;
31039225Sgibbs	u_int	 intstat;
31139225Sgibbs	int	 error;
31239852Simp	board_id_data_t	board_id;
31339225Sgibbs
31439225Sgibbs	/*
31539225Sgibbs	 * See if the three I/O ports look reasonable.
31639225Sgibbs	 * Touch the minimal number of registers in the
31739225Sgibbs	 * failure case.
31839225Sgibbs	 */
31939225Sgibbs	status = aha_inb(aha, STATUS_REG);
32039225Sgibbs	if ((status == 0)
32139225Sgibbs	 || (status & (DIAG_ACTIVE|CMD_REG_BUSY|
32241047Sgibbs		       STATUS_REG_RSVD)) != 0) {
32341047Sgibbs		PRVERB(("%s: status reg test failed %x\n", aha_name(aha),
32441047Sgibbs			status));
32539225Sgibbs		return (ENXIO);
32639225Sgibbs	}
32739225Sgibbs
32839225Sgibbs	intstat = aha_inb(aha, INTSTAT_REG);
32939225Sgibbs	if ((intstat & INTSTAT_REG_RSVD) != 0) {
33041047Sgibbs		PRVERB(("%s: Failed Intstat Reg Test\n", aha_name(aha)));
33139225Sgibbs		return (ENXIO);
33239225Sgibbs	}
33339225Sgibbs
33439225Sgibbs	/*
33541047Sgibbs	 * Looking good so far.  Final test is to reset the
33641047Sgibbs	 * adapter and fetch the board ID and ensure we aren't
33741047Sgibbs	 * looking at a BusLogic.
33841047Sgibbs	 */
33941047Sgibbs	if ((error = ahareset(aha, /*hard_reset*/TRUE)) != 0) {
34041047Sgibbs		if (bootverbose)
34141047Sgibbs			printf("%s: Failed Reset\n", aha_name(aha));
34241047Sgibbs		return (ENXIO);
34341047Sgibbs	}
34441047Sgibbs
34541047Sgibbs	/*
34639852Simp	 * Get the board ID.  We use this to see if we're dealing with
34739852Simp	 * a buslogic card or a aha card (or clone).
34839225Sgibbs	 */
34941047Sgibbs	error = aha_cmd(aha, AOP_INQUIRE_BOARD_ID, NULL, /*parmlen*/0,
35039852Simp		       (u_int8_t*)&board_id, sizeof(board_id),
35139852Simp		       DEFAULT_CMD_TIMEOUT);
35239852Simp	if (error != 0) {
35339881Simp		PRVERB(("%s: INQUIRE failed %x\n", aha_name(aha), error));
35439225Sgibbs		return (ENXIO);
35539225Sgibbs	}
35639852Simp	aha->fw_major = board_id.firmware_rev_major;
35739852Simp	aha->fw_minor = board_id.firmware_rev_minor;
35839852Simp	aha->boardid = board_id.board_type;
35939852Simp
36039225Sgibbs	/*
36139852Simp	 * The Buslogic cards have an id of either 0x41 or 0x42.  So
36239852Simp	 * if those come up in the probe, we test the geometry register
36339852Simp	 * of the board.  Adaptec boards that are this old will not have
36439852Simp	 * this register, and return 0xff, while buslogic cards will return
36539852Simp	 * something different.
36639852Simp	 *
36741335Simp	 * It appears that for reasons unknow, for the for the
36841335Simp	 * aha-1542B cards, we need to wait a little bit before trying
36941335Simp	 * to read the geometry register.  I picked 10ms since we have
37041335Simp	 * reports that a for loop to 1000 did the trick, and this
37141335Simp	 * errs on the side of conservatism.  Besides, no one will
37241335Simp	 * notice a 10mS delay here, even the 1542B card users :-)
37341335Simp	 *
37446997Simp	 * Some compatible cards return 0 here.  Some cards also
37546997Simp	 * seem to return 0x7f.
37641807Simp	 *
37741335Simp	 * XXX I'm not sure how this will impact other cloned cards
37841807Simp	 *
37941807Simp	 * This really should be replaced with the esetup command, since
38046997Simp	 * that appears to be more reliable.  This becomes more and more
38146997Simp	 * true over time as we discover more cards that don't read the
38246997Simp	 * geometry register consistantly.
38339225Sgibbs	 */
38439852Simp	if (aha->boardid <= 0x42) {
38541335Simp		/* Wait 10ms before reading */
38641335Simp		DELAY(10000);
38739852Simp		status = aha_inb(aha, GEOMETRY_REG);
38846997Simp		if (status != 0xff && status != 0x00 && status != 0x7f) {
38944434Simp			PRVERB(("%s: Geometry Register test failed 0x%x\n",
39044434Simp				aha_name(aha), status));
39139852Simp			return (ENXIO);
39241047Sgibbs		}
39339751Simp	}
39439852Simp
39539225Sgibbs	return (0);
39639225Sgibbs}
39739225Sgibbs
39839225Sgibbs/*
39939225Sgibbs * Pull the boards setup information and record it in our softc.
40039225Sgibbs */
40139225Sgibbsint
40239225Sgibbsaha_fetch_adapter_info(struct aha_softc *aha)
40339225Sgibbs{
40439225Sgibbs	setup_data_t	setup_info;
40539225Sgibbs	config_data_t config_data;
40639225Sgibbs	u_int8_t length_param;
40739225Sgibbs	int	 error;
40839751Simp	struct	aha_extbios extbios;
40939225Sgibbs
41039852Simp	switch (aha->boardid) {
41139225Sgibbs	case BOARD_1540_16HEAD_BIOS:
41241514Sarchie		snprintf(aha->model, sizeof(aha->model), "1540 16 head BIOS");
41339225Sgibbs		break;
41439225Sgibbs	case BOARD_1540_64HEAD_BIOS:
41541514Sarchie		snprintf(aha->model, sizeof(aha->model), "1540 64 head BIOS");
41639225Sgibbs		break;
41739225Sgibbs	case BOARD_1542:
41841514Sarchie		snprintf(aha->model, sizeof(aha->model), "1540/1542 64 head BIOS");
41939225Sgibbs		break;
42039225Sgibbs	case BOARD_1640:
42141514Sarchie		snprintf(aha->model, sizeof(aha->model), "1640");
42239225Sgibbs		break;
42339225Sgibbs	case BOARD_1740:
42441514Sarchie		snprintf(aha->model, sizeof(aha->model), "1740A/1742A/1744");
42539225Sgibbs		break;
42639225Sgibbs	case BOARD_1542C:
42741514Sarchie		snprintf(aha->model, sizeof(aha->model), "1542C");
42839225Sgibbs		break;
42939225Sgibbs	case BOARD_1542CF:
43041514Sarchie		snprintf(aha->model, sizeof(aha->model), "1542CF");
43139225Sgibbs		break;
43239225Sgibbs	case BOARD_1542CP:
43341514Sarchie		snprintf(aha->model, sizeof(aha->model), "1542CP");
43439225Sgibbs		break;
43539225Sgibbs	default:
43641514Sarchie		snprintf(aha->model, sizeof(aha->model), "Unknown");
43739225Sgibbs		break;
43839225Sgibbs	}
43939751Simp	/*
44039751Simp	 * If we are a new type of 1542 board (anything newer than a 1542C)
44139751Simp	 * then disable the extended bios so that the
44239751Simp	 * mailbox interface is unlocked.
44339751Simp	 * This is also true for the 1542B Version 3.20. First Adaptec
44439751Simp	 * board that supports >1Gb drives.
44539751Simp	 * No need to check the extended bios flags as some of the
44639751Simp	 * extensions that cause us problems are not flagged in that byte.
44739751Simp	 */
44839751Simp	if (PROBABLY_NEW_BOARD(aha->boardid) ||
44939751Simp		(aha->boardid == 0x41
45039852Simp		&& aha->fw_major == 0x31 &&
45139852Simp		aha->fw_minor >= 0x34)) {
45241047Sgibbs		error = aha_cmd(aha, AOP_RETURN_EXT_BIOS_INFO, NULL,
45339751Simp			/*paramlen*/0, (u_char *)&extbios, sizeof(extbios),
45439751Simp			DEFAULT_CMD_TIMEOUT);
45541047Sgibbs		error = aha_cmd(aha, AOP_MBOX_IF_ENABLE, (u_int8_t *)&extbios,
45639751Simp			/*paramlen*/2, NULL, 0, DEFAULT_CMD_TIMEOUT);
45739751Simp	}
45839751Simp	if (aha->boardid < 0x41)
45941335Simp		printf("%s: Warning: aha-1542A won't likely work.\n",
46039751Simp			aha_name(aha));
46139751Simp
46241335Simp	aha->max_sg = 17;		/* Need >= 17 to do 64k I/O */
46339225Sgibbs	aha->diff_bus = 0;
46439225Sgibbs	aha->extended_lun = 0;
46539751Simp	aha->extended_trans = 0;
46640403Simp	aha->max_ccbs = 16;
46739225Sgibbs	/* Determine Sync/Wide/Disc settings */
46839225Sgibbs	length_param = sizeof(setup_info);
46941047Sgibbs	error = aha_cmd(aha, AOP_INQUIRE_SETUP_INFO, &length_param,
47039225Sgibbs		       /*paramlen*/1, (u_int8_t*)&setup_info,
47139225Sgibbs		       sizeof(setup_info), DEFAULT_CMD_TIMEOUT);
47239225Sgibbs	if (error != 0) {
47339225Sgibbs		printf("%s: aha_fetch_adapter_info - Failed "
47439225Sgibbs		       "Get Setup Info\n", aha_name(aha));
47539225Sgibbs		return (error);
47639225Sgibbs	}
47739225Sgibbs	if (setup_info.initiate_sync != 0) {
47839225Sgibbs		aha->sync_permitted = ALL_TARGETS;
47939225Sgibbs	}
48039225Sgibbs	aha->disc_permitted = ALL_TARGETS;
48139225Sgibbs
48239225Sgibbs	/* We need as many mailboxes as we can have ccbs */
48339225Sgibbs	aha->num_boxes = aha->max_ccbs;
48439225Sgibbs
48539225Sgibbs	/* Determine our SCSI ID */
48639225Sgibbs
48741047Sgibbs	error = aha_cmd(aha, AOP_INQUIRE_CONFIG, NULL, /*parmlen*/0,
48839225Sgibbs		       (u_int8_t*)&config_data, sizeof(config_data),
48939225Sgibbs		       DEFAULT_CMD_TIMEOUT);
49039225Sgibbs	if (error != 0) {
49139225Sgibbs		printf("%s: aha_fetch_adapter_info - Failed Get Config\n",
49239225Sgibbs		       aha_name(aha));
49339225Sgibbs		return (error);
49439225Sgibbs	}
49539225Sgibbs	aha->scsi_id = config_data.scsi_id;
49639225Sgibbs	return (0);
49739225Sgibbs}
49839225Sgibbs
49939225Sgibbs/*
50039225Sgibbs * Start the board, ready for normal operation
50139225Sgibbs */
50239225Sgibbsint
50339225Sgibbsaha_init(struct aha_softc* aha)
50439225Sgibbs{
50539225Sgibbs	/* Announce the Adapter */
50639852Simp	printf("%s: AHA-%s FW Rev. %c.%c (ID=%x) ", aha_name(aha),
50739852Simp	       aha->model, aha->fw_major, aha->fw_minor, aha->boardid);
50839225Sgibbs
50939225Sgibbs	if (aha->diff_bus != 0)
51039225Sgibbs		printf("Diff ");
51139225Sgibbs
51239225Sgibbs	printf("SCSI Host Adapter, SCSI ID %d, %d CCBs\n", aha->scsi_id,
51339225Sgibbs	       aha->max_ccbs);
51439225Sgibbs
51539225Sgibbs	/*
51639225Sgibbs	 * Create our DMA tags.  These tags define the kinds of device
51739225Sgibbs	 * accessable memory allocations and memory mappings we will
51839225Sgibbs	 * need to perform during normal operation.
51939225Sgibbs	 *
52039225Sgibbs	 * Unless we need to further restrict the allocation, we rely
52139225Sgibbs	 * on the restrictions of the parent dmat, hence the common
52239225Sgibbs	 * use of MAXADDR and MAXSIZE.
52339225Sgibbs	 */
52439225Sgibbs
52539225Sgibbs	/* DMA tag for mapping buffers into device visible space. */
52639225Sgibbs	if (bus_dma_tag_create(aha->parent_dmat, /*alignment*/0, /*boundary*/0,
52739225Sgibbs			       /*lowaddr*/BUS_SPACE_MAXADDR,
52839225Sgibbs			       /*highaddr*/BUS_SPACE_MAXADDR,
52939225Sgibbs			       /*filter*/NULL, /*filterarg*/NULL,
53039225Sgibbs			       /*maxsize*/MAXBSIZE, /*nsegments*/AHA_NSEG,
53139225Sgibbs			       /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT,
53239225Sgibbs			       /*flags*/BUS_DMA_ALLOCNOW,
53339225Sgibbs			       &aha->buffer_dmat) != 0) {
53439225Sgibbs		goto error_exit;
53539225Sgibbs	}
53639225Sgibbs
53739225Sgibbs	aha->init_level++;
53839225Sgibbs	/* DMA tag for our mailboxes */
53939225Sgibbs	if (bus_dma_tag_create(aha->parent_dmat, /*alignment*/0, /*boundary*/0,
54039225Sgibbs			       /*lowaddr*/BUS_SPACE_MAXADDR,
54139225Sgibbs			       /*highaddr*/BUS_SPACE_MAXADDR,
54239225Sgibbs			       /*filter*/NULL, /*filterarg*/NULL,
54339225Sgibbs			       aha->num_boxes * (sizeof(aha_mbox_in_t)
54439225Sgibbs					       + sizeof(aha_mbox_out_t)),
54539225Sgibbs			       /*nsegments*/1,
54639225Sgibbs			       /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT,
54739225Sgibbs			       /*flags*/0, &aha->mailbox_dmat) != 0) {
54839225Sgibbs		goto error_exit;
54939225Sgibbs        }
55039225Sgibbs
55139225Sgibbs	aha->init_level++;
55239225Sgibbs
55339225Sgibbs	/* Allocation for our mailboxes */
55439225Sgibbs	if (bus_dmamem_alloc(aha->mailbox_dmat, (void **)&aha->out_boxes,
55539225Sgibbs			     BUS_DMA_NOWAIT, &aha->mailbox_dmamap) != 0) {
55639225Sgibbs		goto error_exit;
55739225Sgibbs	}
55839225Sgibbs
55939225Sgibbs	aha->init_level++;
56039225Sgibbs
56139225Sgibbs	/* And permanently map them */
56239225Sgibbs	bus_dmamap_load(aha->mailbox_dmat, aha->mailbox_dmamap,
56339225Sgibbs       			aha->out_boxes,
56439225Sgibbs			aha->num_boxes * (sizeof(aha_mbox_in_t)
56539225Sgibbs				       + sizeof(aha_mbox_out_t)),
56639225Sgibbs			ahamapmboxes, aha, /*flags*/0);
56739225Sgibbs
56839225Sgibbs	aha->init_level++;
56939225Sgibbs
57039225Sgibbs	aha->in_boxes = (aha_mbox_in_t *)&aha->out_boxes[aha->num_boxes];
57139225Sgibbs
57239225Sgibbs	ahainitmboxes(aha);
57339225Sgibbs
57439225Sgibbs	/* DMA tag for our ccb structures */
57539225Sgibbs	if (bus_dma_tag_create(aha->parent_dmat, /*alignment*/0, /*boundary*/0,
57639225Sgibbs			       /*lowaddr*/BUS_SPACE_MAXADDR,
57739225Sgibbs			       /*highaddr*/BUS_SPACE_MAXADDR,
57839225Sgibbs			       /*filter*/NULL, /*filterarg*/NULL,
57939225Sgibbs			       aha->max_ccbs * sizeof(struct aha_ccb),
58039225Sgibbs			       /*nsegments*/1,
58139225Sgibbs			       /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT,
58239225Sgibbs			       /*flags*/0, &aha->ccb_dmat) != 0) {
58339225Sgibbs		goto error_exit;
58439225Sgibbs        }
58539225Sgibbs
58639225Sgibbs	aha->init_level++;
58739225Sgibbs
58839225Sgibbs	/* Allocation for our ccbs */
58939225Sgibbs	if (bus_dmamem_alloc(aha->ccb_dmat, (void **)&aha->aha_ccb_array,
59039225Sgibbs			     BUS_DMA_NOWAIT, &aha->ccb_dmamap) != 0) {
59139225Sgibbs		goto error_exit;
59239225Sgibbs	}
59339225Sgibbs
59439225Sgibbs	aha->init_level++;
59539225Sgibbs
59639225Sgibbs	/* And permanently map them */
59739225Sgibbs	bus_dmamap_load(aha->ccb_dmat, aha->ccb_dmamap,
59839225Sgibbs       			aha->aha_ccb_array,
59939225Sgibbs			aha->max_ccbs * sizeof(struct aha_ccb),
60039225Sgibbs			ahamapccbs, aha, /*flags*/0);
60139225Sgibbs
60239225Sgibbs	aha->init_level++;
60339225Sgibbs
60439225Sgibbs	/* DMA tag for our S/G structures.  We allocate in page sized chunks */
60539225Sgibbs	if (bus_dma_tag_create(aha->parent_dmat, /*alignment*/0, /*boundary*/0,
60639225Sgibbs			       /*lowaddr*/BUS_SPACE_MAXADDR,
60739225Sgibbs			       /*highaddr*/BUS_SPACE_MAXADDR,
60839225Sgibbs			       /*filter*/NULL, /*filterarg*/NULL,
60939225Sgibbs			       PAGE_SIZE, /*nsegments*/1,
61039225Sgibbs			       /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT,
61139225Sgibbs			       /*flags*/0, &aha->sg_dmat) != 0) {
61239225Sgibbs		goto error_exit;
61339225Sgibbs        }
61439225Sgibbs
61539225Sgibbs	aha->init_level++;
61639225Sgibbs
61739225Sgibbs	/* Perform initial CCB allocation */
61839225Sgibbs	bzero(aha->aha_ccb_array, aha->max_ccbs * sizeof(struct aha_ccb));
61939225Sgibbs	ahaallocccbs(aha);
62039225Sgibbs
62139225Sgibbs	if (aha->num_ccbs == 0) {
62239324Sgibbs		printf("%s: aha_init - Unable to allocate initial ccbs\n",
62339324Sgibbs		       aha_name(aha));
62439225Sgibbs		goto error_exit;
62539225Sgibbs	}
62639225Sgibbs
62739225Sgibbs	/*
62839225Sgibbs	 * Note that we are going and return (to probe)
62939225Sgibbs	 */
63039225Sgibbs	return 0;
63139225Sgibbs
63239225Sgibbserror_exit:
63339225Sgibbs
63439225Sgibbs	return (ENXIO);
63539225Sgibbs}
63639225Sgibbs
63739225Sgibbsint
63839225Sgibbsaha_attach(struct aha_softc *aha)
63939225Sgibbs{
64039225Sgibbs	int tagged_dev_openings;
64139225Sgibbs	struct cam_devq *devq;
64239225Sgibbs
64339225Sgibbs	/*
64441335Simp	 * We don't do tagged queueing, since the aha cards don't
64541335Simp	 * support it.
64639225Sgibbs	 */
64739225Sgibbs	tagged_dev_openings = 0;
64839225Sgibbs
64939225Sgibbs	/*
65039225Sgibbs	 * Create the device queue for our SIM.
65139225Sgibbs	 */
65239225Sgibbs	devq = cam_simq_alloc(aha->max_ccbs - 1);
65339225Sgibbs	if (devq == NULL)
65439225Sgibbs		return (ENOMEM);
65539225Sgibbs
65639225Sgibbs	/*
65739225Sgibbs	 * Construct our SIM entry
65839225Sgibbs	 */
65939225Sgibbs	aha->sim = cam_sim_alloc(ahaaction, ahapoll, "aha", aha, aha->unit,
66039225Sgibbs				2, tagged_dev_openings, devq);
66139225Sgibbs	if (aha->sim == NULL) {
66239225Sgibbs		cam_simq_free(devq);
66339225Sgibbs		return (ENOMEM);
66439225Sgibbs	}
66539225Sgibbs
66639225Sgibbs	if (xpt_bus_register(aha->sim, 0) != CAM_SUCCESS) {
66739225Sgibbs		cam_sim_free(aha->sim, /*free_devq*/TRUE);
66839225Sgibbs		return (ENXIO);
66939225Sgibbs	}
67039225Sgibbs
67139225Sgibbs	if (xpt_create_path(&aha->path, /*periph*/NULL,
67239225Sgibbs			    cam_sim_path(aha->sim), CAM_TARGET_WILDCARD,
67339225Sgibbs			    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
67439225Sgibbs		xpt_bus_deregister(cam_sim_path(aha->sim));
67539225Sgibbs		cam_sim_free(aha->sim, /*free_devq*/TRUE);
67639225Sgibbs		return (ENXIO);
67739225Sgibbs	}
67839225Sgibbs
67939225Sgibbs	return (0);
68039225Sgibbs}
68139225Sgibbs
68239225Sgibbschar *
68339225Sgibbsaha_name(struct aha_softc *aha)
68439225Sgibbs{
68539225Sgibbs	static char name[10];
68639225Sgibbs
68741514Sarchie	snprintf(name, sizeof(name), "aha%d", aha->unit);
68839225Sgibbs	return (name);
68939225Sgibbs}
69039225Sgibbs
69139225Sgibbsint
69239225Sgibbsaha_check_probed_iop(u_int ioport)
69339225Sgibbs{
69439225Sgibbs	u_int i;
69539225Sgibbs
69639225Sgibbs	for (i=0; i < AHA_NUM_ISAPORTS; i++) {
69739225Sgibbs		if (aha_isa_ports[i].addr == ioport) {
69839225Sgibbs			if (aha_isa_ports[i].probed != 0)
69939225Sgibbs				return (1);
70039225Sgibbs			else {
70139225Sgibbs				return (0);
70239225Sgibbs			}
70339225Sgibbs		}
70439225Sgibbs	}
70539225Sgibbs	return (1);
70639225Sgibbs}
70739225Sgibbs
70839225Sgibbsvoid
70939225Sgibbsaha_mark_probed_bio(isa_compat_io_t port)
71039225Sgibbs{
71139225Sgibbs	if (port < BIO_DISABLED)
71241047Sgibbs		aha_mark_probed_iop(aha_board_ports[port]);
71339225Sgibbs}
71439225Sgibbs
71539225Sgibbsvoid
71639225Sgibbsaha_mark_probed_iop(u_int ioport)
71739225Sgibbs{
71839225Sgibbs	u_int i;
71939225Sgibbs
72039225Sgibbs	for (i = 0; i < AHA_NUM_ISAPORTS; i++) {
72139225Sgibbs		if (ioport == aha_isa_ports[i].addr) {
72239225Sgibbs			aha_isa_ports[i].probed = 1;
72339225Sgibbs			break;
72439225Sgibbs		}
72539225Sgibbs	}
72639225Sgibbs}
72739225Sgibbs
72841047Sgibbsvoid
72941047Sgibbsaha_find_probe_range(int ioport, int *port_index, int *max_port_index)
73041047Sgibbs{
73141047Sgibbs	if (ioport > 0) {
73241047Sgibbs		int i;
73341047Sgibbs
73441047Sgibbs		for (i = 0;i < AHA_NUM_ISAPORTS; i++)
73541047Sgibbs			if (ioport <= aha_isa_ports[i].addr)
73641047Sgibbs				break;
73741047Sgibbs		if ((i >= AHA_NUM_ISAPORTS)
73841047Sgibbs		 || (ioport != aha_isa_ports[i].addr)) {
73942013Sgibbs			printf("\n"
74042013Sgibbs"aha_isa_probe: Invalid baseport of 0x%x specified.\n"
74142013Sgibbs"aha_isa_probe: Nearest valid baseport is 0x%x.\n"
74242013Sgibbs"aha_isa_probe: Failing probe.\n",
74341047Sgibbs			       ioport,
74441047Sgibbs			       (i < AHA_NUM_ISAPORTS)
74541047Sgibbs				    ? aha_isa_ports[i].addr
74641047Sgibbs				    : aha_isa_ports[AHA_NUM_ISAPORTS - 1].addr);
74741047Sgibbs			*port_index = *max_port_index = -1;
74841047Sgibbs			return;
74941047Sgibbs		}
75041047Sgibbs		*port_index = *max_port_index = aha_isa_ports[i].bio;
75141047Sgibbs	} else {
75241047Sgibbs		*port_index = 0;
75341047Sgibbs		*max_port_index = AHA_NUM_ISAPORTS - 1;
75441047Sgibbs	}
75541047Sgibbs}
75641047Sgibbs
75741047Sgibbsint
75841047Sgibbsaha_iop_from_bio(isa_compat_io_t bio_index)
75941047Sgibbs{
76041047Sgibbs	if (bio_index >= 0 && bio_index < AHA_NUM_ISAPORTS)
76141047Sgibbs		return (aha_board_ports[bio_index]);
76241047Sgibbs	return (-1);
76341047Sgibbs}
76441047Sgibbs
76539225Sgibbsstatic void
76639225Sgibbsahaallocccbs(struct aha_softc *aha)
76739225Sgibbs{
76839225Sgibbs	struct aha_ccb *next_ccb;
76939225Sgibbs	struct sg_map_node *sg_map;
77039225Sgibbs	bus_addr_t physaddr;
77139225Sgibbs	aha_sg_t *segs;
77239225Sgibbs	int newcount;
77339225Sgibbs	int i;
77439225Sgibbs
77539225Sgibbs	next_ccb = &aha->aha_ccb_array[aha->num_ccbs];
77639225Sgibbs
77739225Sgibbs	sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT);
77839225Sgibbs
77939225Sgibbs	if (sg_map == NULL)
78039225Sgibbs		return;
78139225Sgibbs
78239225Sgibbs	/* Allocate S/G space for the next batch of CCBS */
78339225Sgibbs	if (bus_dmamem_alloc(aha->sg_dmat, (void **)&sg_map->sg_vaddr,
78439225Sgibbs			     BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) {
78539225Sgibbs		free(sg_map, M_DEVBUF);
78639225Sgibbs		return;
78739225Sgibbs	}
78839225Sgibbs
78939225Sgibbs	SLIST_INSERT_HEAD(&aha->sg_maps, sg_map, links);
79039225Sgibbs
79139225Sgibbs	bus_dmamap_load(aha->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr,
79239225Sgibbs			PAGE_SIZE, ahamapsgs, aha, /*flags*/0);
79339225Sgibbs
79439225Sgibbs	segs = sg_map->sg_vaddr;
79539225Sgibbs	physaddr = sg_map->sg_physaddr;
79639225Sgibbs
79739225Sgibbs	newcount = (PAGE_SIZE / (AHA_NSEG * sizeof(aha_sg_t)));
79839225Sgibbs	for (i = 0; aha->num_ccbs < aha->max_ccbs && i < newcount; i++) {
79939225Sgibbs		int error;
80039225Sgibbs
80139225Sgibbs		next_ccb->sg_list = segs;
80239225Sgibbs		next_ccb->sg_list_phys = physaddr;
80341047Sgibbs		next_ccb->flags = ACCB_FREE;
80439225Sgibbs		error = bus_dmamap_create(aha->buffer_dmat, /*flags*/0,
80539225Sgibbs					  &next_ccb->dmamap);
80639225Sgibbs		if (error != 0)
80739225Sgibbs			break;
80839225Sgibbs		SLIST_INSERT_HEAD(&aha->free_aha_ccbs, next_ccb, links);
80939225Sgibbs		segs += AHA_NSEG;
81039225Sgibbs		physaddr += (AHA_NSEG * sizeof(aha_sg_t));
81139225Sgibbs		next_ccb++;
81239225Sgibbs		aha->num_ccbs++;
81339225Sgibbs	}
81439225Sgibbs
81539225Sgibbs	/* Reserve a CCB for error recovery */
81641047Sgibbs	if (aha->recovery_accb == NULL) {
81741047Sgibbs		aha->recovery_accb = SLIST_FIRST(&aha->free_aha_ccbs);
81839225Sgibbs		SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links);
81939225Sgibbs	}
82039225Sgibbs}
82139225Sgibbs
82239225Sgibbsstatic __inline void
82341047Sgibbsahafreeccb(struct aha_softc *aha, struct aha_ccb *accb)
82439225Sgibbs{
82539225Sgibbs	int s;
82639225Sgibbs
82739225Sgibbs	s = splcam();
82841047Sgibbs	if ((accb->flags & ACCB_ACTIVE) != 0)
82941047Sgibbs		LIST_REMOVE(&accb->ccb->ccb_h, sim_links.le);
83039225Sgibbs	if (aha->resource_shortage != 0
83141047Sgibbs	 && (accb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) {
83241047Sgibbs		accb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
83339225Sgibbs		aha->resource_shortage = FALSE;
83439225Sgibbs	}
83541047Sgibbs	accb->flags = ACCB_FREE;
83641047Sgibbs	SLIST_INSERT_HEAD(&aha->free_aha_ccbs, accb, links);
83741047Sgibbs	aha->active_ccbs--;
83839225Sgibbs	splx(s);
83939225Sgibbs}
84039225Sgibbs
84139225Sgibbsstatic struct aha_ccb*
84239225Sgibbsahagetccb(struct aha_softc *aha)
84339225Sgibbs{
84441047Sgibbs	struct	aha_ccb* accb;
84539225Sgibbs	int	s;
84639225Sgibbs
84739225Sgibbs	s = splcam();
84841047Sgibbs	if ((accb = SLIST_FIRST(&aha->free_aha_ccbs)) != NULL) {
84939225Sgibbs		SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links);
85041047Sgibbs		aha->active_ccbs++;
85139225Sgibbs	} else if (aha->num_ccbs < aha->max_ccbs) {
85239225Sgibbs		ahaallocccbs(aha);
85341047Sgibbs		accb = SLIST_FIRST(&aha->free_aha_ccbs);
85441047Sgibbs		if (accb == NULL)
85541047Sgibbs			printf("%s: Can't malloc ACCB\n", aha_name(aha));
85641047Sgibbs		else {
85739225Sgibbs			SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links);
85841047Sgibbs			aha->active_ccbs++;
85941047Sgibbs		}
86039225Sgibbs	}
86139225Sgibbs	splx(s);
86239225Sgibbs
86341047Sgibbs	return (accb);
86439225Sgibbs}
86539225Sgibbs
86639225Sgibbsstatic void
86739225Sgibbsahaaction(struct cam_sim *sim, union ccb *ccb)
86839225Sgibbs{
86939225Sgibbs	struct	aha_softc *aha;
87039225Sgibbs
87139225Sgibbs	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahaaction\n"));
87239225Sgibbs
87339225Sgibbs	aha = (struct aha_softc *)cam_sim_softc(sim);
87439225Sgibbs
87539225Sgibbs	switch (ccb->ccb_h.func_code) {
87639225Sgibbs	/* Common cases first */
87739225Sgibbs	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
87839225Sgibbs	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
87939225Sgibbs	{
88041047Sgibbs		struct	aha_ccb	*accb;
88139225Sgibbs		struct	aha_hccb *hccb;
88239225Sgibbs
88339225Sgibbs		/*
88441047Sgibbs		 * get a accb to use.
88539225Sgibbs		 */
88641047Sgibbs		if ((accb = ahagetccb(aha)) == NULL) {
88739225Sgibbs			int s;
88839225Sgibbs
88939225Sgibbs			s = splcam();
89039225Sgibbs			aha->resource_shortage = TRUE;
89139225Sgibbs			splx(s);
89239225Sgibbs			xpt_freeze_simq(aha->sim, /*count*/1);
89339225Sgibbs			ccb->ccb_h.status = CAM_REQUEUE_REQ;
89439225Sgibbs			xpt_done(ccb);
89539225Sgibbs			return;
89639225Sgibbs		}
89739225Sgibbs
89841047Sgibbs		hccb = &accb->hccb;
89939225Sgibbs
90039225Sgibbs		/*
90141047Sgibbs		 * So we can find the ACCB when an abort is requested
90239225Sgibbs		 */
90341047Sgibbs		accb->ccb = ccb;
90441047Sgibbs		ccb->ccb_h.ccb_accb_ptr = accb;
90539225Sgibbs		ccb->ccb_h.ccb_aha_ptr = aha;
90639225Sgibbs
90739225Sgibbs		/*
90841047Sgibbs		 * Put all the arguments for the xfer in the accb
90939225Sgibbs		 */
91039225Sgibbs		hccb->target = ccb->ccb_h.target_id;
91139225Sgibbs		hccb->lun = ccb->ccb_h.target_lun;
91239225Sgibbs		hccb->ahastat = 0;
91339225Sgibbs		hccb->sdstat = 0;
91439225Sgibbs
91539225Sgibbs		if (ccb->ccb_h.func_code == XPT_SCSI_IO) {
91639225Sgibbs			struct ccb_scsiio *csio;
91739225Sgibbs			struct ccb_hdr *ccbh;
91839225Sgibbs
91939225Sgibbs			csio = &ccb->csio;
92039225Sgibbs			ccbh = &csio->ccb_h;
92142887Simp			hccb->opcode = aha->ccb_ccb_opcode;
92239225Sgibbs			hccb->datain = (ccb->ccb_h.flags & CAM_DIR_IN) != 0;
92339225Sgibbs			hccb->dataout = (ccb->ccb_h.flags & CAM_DIR_OUT) != 0;
92439225Sgibbs			hccb->cmd_len = csio->cdb_len;
92539225Sgibbs			if (hccb->cmd_len > sizeof(hccb->scsi_cdb)) {
92639225Sgibbs				ccb->ccb_h.status = CAM_REQ_INVALID;
92741047Sgibbs				ahafreeccb(aha, accb);
92839225Sgibbs				xpt_done(ccb);
92939225Sgibbs				return;
93039225Sgibbs			}
93139225Sgibbs			hccb->sense_len = csio->sense_len;
93239225Sgibbs			if ((ccbh->flags & CAM_CDB_POINTER) != 0) {
93339225Sgibbs				if ((ccbh->flags & CAM_CDB_PHYS) == 0) {
93439225Sgibbs					bcopy(csio->cdb_io.cdb_ptr,
93539225Sgibbs					      hccb->scsi_cdb, hccb->cmd_len);
93639225Sgibbs				} else {
93739225Sgibbs					/* I guess I could map it in... */
93839225Sgibbs					ccbh->status = CAM_REQ_INVALID;
93941047Sgibbs					ahafreeccb(aha, accb);
94039225Sgibbs					xpt_done(ccb);
94139225Sgibbs					return;
94239225Sgibbs				}
94339225Sgibbs			} else {
94439225Sgibbs				bcopy(csio->cdb_io.cdb_bytes,
94539225Sgibbs				      hccb->scsi_cdb, hccb->cmd_len);
94639225Sgibbs			}
94739225Sgibbs			/*
94839225Sgibbs			 * If we have any data to send with this command,
94939225Sgibbs			 * map it into bus space.
95039225Sgibbs			 */
95139225Sgibbs		        /* Only use S/G if there is a transfer */
95239225Sgibbs			if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
95339225Sgibbs				if ((ccbh->flags & CAM_SCATTER_VALID) == 0) {
95439225Sgibbs					/*
95539225Sgibbs					 * We've been given a pointer
95639225Sgibbs					 * to a single buffer.
95739225Sgibbs					 */
95839225Sgibbs					if ((ccbh->flags & CAM_DATA_PHYS)==0) {
95939225Sgibbs						int s;
96039225Sgibbs						int error;
96139225Sgibbs
96239225Sgibbs						s = splsoftvm();
96339225Sgibbs						error = bus_dmamap_load(
96439225Sgibbs						    aha->buffer_dmat,
96541047Sgibbs						    accb->dmamap,
96639225Sgibbs						    csio->data_ptr,
96739225Sgibbs						    csio->dxfer_len,
96839225Sgibbs						    ahaexecuteccb,
96941047Sgibbs						    accb,
97039225Sgibbs						    /*flags*/0);
97139225Sgibbs						if (error == EINPROGRESS) {
97239225Sgibbs							/*
97339225Sgibbs							 * So as to maintain
97439225Sgibbs							 * ordering, freeze the
97539225Sgibbs							 * controller queue
97639225Sgibbs							 * until our mapping is
97739225Sgibbs							 * returned.
97839225Sgibbs							 */
97939225Sgibbs							xpt_freeze_simq(aha->sim,
98039225Sgibbs									1);
98139225Sgibbs							csio->ccb_h.status |=
98239225Sgibbs							    CAM_RELEASE_SIMQ;
98339225Sgibbs						}
98439225Sgibbs						splx(s);
98539225Sgibbs					} else {
98639225Sgibbs						struct bus_dma_segment seg;
98739225Sgibbs
98839225Sgibbs						/* Pointer to physical buffer */
98939225Sgibbs						seg.ds_addr =
99039225Sgibbs						    (bus_addr_t)csio->data_ptr;
99139225Sgibbs						seg.ds_len = csio->dxfer_len;
99241047Sgibbs						ahaexecuteccb(accb, &seg, 1, 0);
99339225Sgibbs					}
99439225Sgibbs				} else {
99539225Sgibbs					struct bus_dma_segment *segs;
99639225Sgibbs
99739225Sgibbs					if ((ccbh->flags & CAM_DATA_PHYS) != 0)
99839225Sgibbs						panic("ahaaction - Physical "
99939225Sgibbs						      "segment pointers "
100039225Sgibbs						      "unsupported");
100139225Sgibbs
100239225Sgibbs					if ((ccbh->flags&CAM_SG_LIST_PHYS)==0)
100339225Sgibbs						panic("ahaaction - Virtual "
100439225Sgibbs						      "segment addresses "
100539225Sgibbs						      "unsupported");
100639225Sgibbs
100739225Sgibbs					/* Just use the segments provided */
100839225Sgibbs					segs = (struct bus_dma_segment *)
100939225Sgibbs					    csio->data_ptr;
101041047Sgibbs					ahaexecuteccb(accb, segs,
101139225Sgibbs						     csio->sglist_cnt, 0);
101239225Sgibbs				}
101339225Sgibbs			} else {
101441047Sgibbs				ahaexecuteccb(accb, NULL, 0, 0);
101539225Sgibbs			}
101639225Sgibbs		} else {
101739225Sgibbs			hccb->opcode = INITIATOR_BUS_DEV_RESET;
101839225Sgibbs			/* No data transfer */
101939225Sgibbs			hccb->datain = TRUE;
102039225Sgibbs			hccb->dataout = TRUE;
102139225Sgibbs			hccb->cmd_len = 0;
102239225Sgibbs			hccb->sense_len = 0;
102341047Sgibbs			ahaexecuteccb(accb, NULL, 0, 0);
102439225Sgibbs		}
102539225Sgibbs		break;
102639225Sgibbs	}
102739225Sgibbs	case XPT_EN_LUN:		/* Enable LUN as a target */
102839225Sgibbs	case XPT_TARGET_IO:		/* Execute target I/O request */
102939225Sgibbs	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
103039225Sgibbs	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/
103139225Sgibbs	case XPT_ABORT:			/* Abort the specified CCB */
103239225Sgibbs		/* XXX Implement */
103339225Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
103439225Sgibbs		xpt_done(ccb);
103539225Sgibbs		break;
103639225Sgibbs	case XPT_SET_TRAN_SETTINGS:
103739225Sgibbs	{
103839225Sgibbs		/* XXX Implement */
103946581Sken		ccb->ccb_h.status = CAM_PROVIDE_FAIL;
104039225Sgibbs		xpt_done(ccb);
104139225Sgibbs		break;
104239225Sgibbs	}
104339225Sgibbs	case XPT_GET_TRAN_SETTINGS:
104439225Sgibbs	/* Get default/user set transfer settings for the target */
104539225Sgibbs	{
104639225Sgibbs		struct	ccb_trans_settings *cts;
104739225Sgibbs		u_int	target_mask;
104839225Sgibbs
104939225Sgibbs		cts = &ccb->cts;
105039225Sgibbs		target_mask = 0x01 << ccb->ccb_h.target_id;
105139225Sgibbs		if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) {
105239225Sgibbs			cts->flags = 0;
105339225Sgibbs			if ((aha->disc_permitted & target_mask) != 0)
105439225Sgibbs				cts->flags |= CCB_TRANS_DISC_ENB;
105539225Sgibbs			cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
105647506Sgibbs			if ((aha->sync_permitted & target_mask) != 0) {
105747506Sgibbs				if (aha->boardid >= BOARD_1542CF)
105847506Sgibbs					cts->sync_period = 25;
105947506Sgibbs				else
106047506Sgibbs					cts->sync_period = 50;
106147506Sgibbs			} else
106239225Sgibbs				cts->sync_period = 0;
106339225Sgibbs
106439225Sgibbs			if (cts->sync_period != 0)
106539225Sgibbs				cts->sync_offset = 15;
106639225Sgibbs
106739225Sgibbs			cts->valid = CCB_TRANS_SYNC_RATE_VALID
106839225Sgibbs				   | CCB_TRANS_SYNC_OFFSET_VALID
106939225Sgibbs				   | CCB_TRANS_BUS_WIDTH_VALID
107039225Sgibbs				   | CCB_TRANS_DISC_VALID
107139225Sgibbs				   | CCB_TRANS_TQ_VALID;
107239225Sgibbs		} else {
107339225Sgibbs			ahafetchtransinfo(aha, cts);
107439225Sgibbs		}
107539225Sgibbs
107639225Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
107739225Sgibbs		xpt_done(ccb);
107839225Sgibbs		break;
107939225Sgibbs	}
108039225Sgibbs	case XPT_CALC_GEOMETRY:
108139225Sgibbs	{
108239225Sgibbs		struct	  ccb_calc_geometry *ccg;
108339225Sgibbs		u_int32_t size_mb;
108439225Sgibbs		u_int32_t secs_per_cylinder;
108539225Sgibbs
108639225Sgibbs		ccg = &ccb->ccg;
108739225Sgibbs		size_mb = ccg->volume_size
108839225Sgibbs			/ ((1024L * 1024L) / ccg->block_size);
108939225Sgibbs
109039225Sgibbs		if (size_mb >= 1024 && (aha->extended_trans != 0)) {
109139225Sgibbs			if (size_mb >= 2048) {
109239225Sgibbs				ccg->heads = 255;
109339225Sgibbs				ccg->secs_per_track = 63;
109439225Sgibbs			} else {
109539225Sgibbs				ccg->heads = 128;
109639225Sgibbs				ccg->secs_per_track = 32;
109739225Sgibbs			}
109839225Sgibbs		} else {
109939225Sgibbs			ccg->heads = 64;
110039225Sgibbs			ccg->secs_per_track = 32;
110139225Sgibbs		}
110239225Sgibbs		secs_per_cylinder = ccg->heads * ccg->secs_per_track;
110339225Sgibbs		ccg->cylinders = ccg->volume_size / secs_per_cylinder;
110439225Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
110539225Sgibbs		xpt_done(ccb);
110639225Sgibbs		break;
110739225Sgibbs	}
110839225Sgibbs	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
110939225Sgibbs	{
111039225Sgibbs		ahareset(aha, /*hardreset*/TRUE);
111139225Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
111239225Sgibbs		xpt_done(ccb);
111339225Sgibbs		break;
111439225Sgibbs	}
111539225Sgibbs	case XPT_TERM_IO:		/* Terminate the I/O process */
111639225Sgibbs		/* XXX Implement */
111739225Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
111839225Sgibbs		xpt_done(ccb);
111939225Sgibbs		break;
112039225Sgibbs	case XPT_PATH_INQ:		/* Path routing inquiry */
112139225Sgibbs	{
112239225Sgibbs		struct ccb_pathinq *cpi = &ccb->cpi;
112339225Sgibbs
112439225Sgibbs		cpi->version_num = 1; /* XXX??? */
112539225Sgibbs		cpi->hba_inquiry = PI_SDTR_ABLE;
112639225Sgibbs		cpi->target_sprt = 0;
112739225Sgibbs		cpi->hba_misc = 0;
112839225Sgibbs		cpi->hba_eng_cnt = 0;
112939852Simp		cpi->max_target = 7;
113039225Sgibbs		cpi->max_lun = 7;
113139225Sgibbs		cpi->initiator_id = aha->scsi_id;
113239225Sgibbs		cpi->bus_id = cam_sim_bus(sim);
113346581Sken		cpi->base_transfer_speed = 3300;
113439225Sgibbs		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
113539225Sgibbs		strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN);
113639225Sgibbs		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
113739225Sgibbs		cpi->unit_number = cam_sim_unit(sim);
113839225Sgibbs		cpi->ccb_h.status = CAM_REQ_CMP;
113939225Sgibbs		xpt_done(ccb);
114039225Sgibbs		break;
114139225Sgibbs	}
114239225Sgibbs	default:
114339225Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
114439225Sgibbs		xpt_done(ccb);
114539225Sgibbs		break;
114639225Sgibbs	}
114739225Sgibbs}
114839225Sgibbs
114939225Sgibbsstatic void
115039225Sgibbsahaexecuteccb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
115139225Sgibbs{
115241047Sgibbs	struct	 aha_ccb *accb;
115339225Sgibbs	union	 ccb *ccb;
115439225Sgibbs	struct	 aha_softc *aha;
115540419Sgibbs	int	 s;
115639225Sgibbs	u_int32_t paddr;
115739225Sgibbs
115841047Sgibbs	accb = (struct aha_ccb *)arg;
115941047Sgibbs	ccb = accb->ccb;
116039225Sgibbs	aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr;
116139225Sgibbs
116239225Sgibbs	if (error != 0) {
116339225Sgibbs		if (error != EFBIG)
116439225Sgibbs			printf("%s: Unexepected error 0x%x returned from "
116539324Sgibbs			       "bus_dmamap_load\n", aha_name(aha), error);
116639225Sgibbs		if (ccb->ccb_h.status == CAM_REQ_INPROG) {
116739225Sgibbs			xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
116839225Sgibbs			ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN;
116939225Sgibbs		}
117041047Sgibbs		ahafreeccb(aha, accb);
117139225Sgibbs		xpt_done(ccb);
117239225Sgibbs		return;
117339225Sgibbs	}
117439225Sgibbs
117539225Sgibbs	if (nseg != 0) {
117639225Sgibbs		aha_sg_t *sg;
117739225Sgibbs		bus_dma_segment_t *end_seg;
117839225Sgibbs		bus_dmasync_op_t op;
117939225Sgibbs
118039225Sgibbs		end_seg = dm_segs + nseg;
118139225Sgibbs
118239225Sgibbs		/* Copy the segments into our SG list */
118341047Sgibbs		sg = accb->sg_list;
118439225Sgibbs		while (dm_segs < end_seg) {
118539225Sgibbs			ahautoa24(dm_segs->ds_len, sg->len);
118639225Sgibbs			ahautoa24(dm_segs->ds_addr, sg->addr);
118739225Sgibbs			sg++;
118839225Sgibbs			dm_segs++;
118939225Sgibbs		}
119039225Sgibbs
119139225Sgibbs		if (nseg > 1) {
119242887Simp			accb->hccb.opcode = aha->ccb_sg_opcode;
119339225Sgibbs			ahautoa24((sizeof(aha_sg_t) * nseg),
119441047Sgibbs				  accb->hccb.data_len);
119541047Sgibbs			ahautoa24(accb->sg_list_phys, accb->hccb.data_addr);
119639225Sgibbs		} else {
119741047Sgibbs			bcopy(accb->sg_list->len, accb->hccb.data_len, 3);
119841047Sgibbs			bcopy(accb->sg_list->addr, accb->hccb.data_addr, 3);
119939225Sgibbs		}
120039225Sgibbs
120139225Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
120239225Sgibbs			op = BUS_DMASYNC_PREREAD;
120339225Sgibbs		else
120439225Sgibbs			op = BUS_DMASYNC_PREWRITE;
120539225Sgibbs
120641047Sgibbs		bus_dmamap_sync(aha->buffer_dmat, accb->dmamap, op);
120739225Sgibbs
120839225Sgibbs	} else {
120941709Sgibbs		accb->hccb.opcode = INITIATOR_CCB;
121041047Sgibbs		ahautoa24(0, accb->hccb.data_len);
121141047Sgibbs		ahautoa24(0, accb->hccb.data_addr);
121239225Sgibbs	}
121339225Sgibbs
121439225Sgibbs	s = splcam();
121539225Sgibbs
121639225Sgibbs	/*
121739225Sgibbs	 * Last time we need to check if this CCB needs to
121839225Sgibbs	 * be aborted.
121939225Sgibbs	 */
122039225Sgibbs	if (ccb->ccb_h.status != CAM_REQ_INPROG) {
122139225Sgibbs		if (nseg != 0)
122241047Sgibbs			bus_dmamap_unload(aha->buffer_dmat, accb->dmamap);
122341047Sgibbs		ahafreeccb(aha, accb);
122439225Sgibbs		xpt_done(ccb);
122539225Sgibbs		splx(s);
122639225Sgibbs		return;
122739225Sgibbs	}
122839225Sgibbs
122941047Sgibbs	accb->flags = ACCB_ACTIVE;
123039225Sgibbs	ccb->ccb_h.status |= CAM_SIM_QUEUED;
123139225Sgibbs	LIST_INSERT_HEAD(&aha->pending_ccbs, &ccb->ccb_h, sim_links.le);
123239225Sgibbs
123339225Sgibbs	ccb->ccb_h.timeout_ch =
123441047Sgibbs	    timeout(ahatimeout, (caddr_t)accb,
123539225Sgibbs		    (ccb->ccb_h.timeout * hz) / 1000);
123639225Sgibbs
123739225Sgibbs	/* Tell the adapter about this command */
123841047Sgibbs	if (aha->cur_outbox->action_code != AMBO_FREE) {
123941047Sgibbs		/*
124041047Sgibbs		 * We should never encounter a busy mailbox.
124141047Sgibbs		 * If we do, warn the user, and treat it as
124241047Sgibbs		 * a resource shortage.  If the controller is
124341047Sgibbs		 * hung, one of the pending transactions will
124441047Sgibbs		 * timeout causing us to start recovery operations.
124541047Sgibbs		 */
124641047Sgibbs		printf("%s: Encountered busy mailbox with %d out of %d "
124741047Sgibbs		       "commands active!!!", aha_name(aha), aha->active_ccbs,
124841047Sgibbs		       aha->max_ccbs);
124941047Sgibbs		untimeout(ahatimeout, accb, ccb->ccb_h.timeout_ch);
125041047Sgibbs		if (nseg != 0)
125141047Sgibbs			bus_dmamap_unload(aha->buffer_dmat, accb->dmamap);
125241047Sgibbs		ahafreeccb(aha, accb);
125341047Sgibbs		aha->resource_shortage = TRUE;
125441047Sgibbs		xpt_freeze_simq(aha->sim, /*count*/1);
125541047Sgibbs		ccb->ccb_h.status = CAM_REQUEUE_REQ;
125641047Sgibbs		xpt_done(ccb);
125741047Sgibbs		return;
125841047Sgibbs	}
125941047Sgibbs	paddr = ahaccbvtop(aha, accb);
126039225Sgibbs	ahautoa24(paddr, aha->cur_outbox->ccb_addr);
126141047Sgibbs	aha->cur_outbox->action_code = AMBO_START;
126241047Sgibbs	aha_outb(aha, COMMAND_REG, AOP_START_MBOX);
126339225Sgibbs
126439225Sgibbs	ahanextoutbox(aha);
126539225Sgibbs	splx(s);
126639225Sgibbs}
126739225Sgibbs
126839225Sgibbsvoid
126939225Sgibbsaha_intr(void *arg)
127039225Sgibbs{
127139225Sgibbs	struct	aha_softc *aha;
127239225Sgibbs	u_int	intstat;
127339225Sgibbs
127439225Sgibbs	aha = (struct aha_softc *)arg;
127539225Sgibbs	while (((intstat = aha_inb(aha, INTSTAT_REG)) & INTR_PENDING) != 0) {
127639225Sgibbs		if ((intstat & CMD_COMPLETE) != 0) {
127739225Sgibbs			aha->latched_status = aha_inb(aha, STATUS_REG);
127839225Sgibbs			aha->command_cmp = TRUE;
127939225Sgibbs		}
128039225Sgibbs
128139225Sgibbs		aha_outb(aha, CONTROL_REG, RESET_INTR);
128239225Sgibbs
128339225Sgibbs		if ((intstat & IMB_LOADED) != 0) {
128441047Sgibbs			while (aha->cur_inbox->comp_code != AMBI_FREE) {
128539225Sgibbs				u_int32_t	paddr;
128639225Sgibbs				paddr = aha_a24tou(aha->cur_inbox->ccb_addr);
128739225Sgibbs				ahadone(aha,
128839225Sgibbs				       ahaccbptov(aha, paddr),
128939225Sgibbs				       aha->cur_inbox->comp_code);
129041047Sgibbs				aha->cur_inbox->comp_code = AMBI_FREE;
129139225Sgibbs				ahanextinbox(aha);
129239225Sgibbs			}
129339225Sgibbs		}
129439225Sgibbs
129539225Sgibbs		if ((intstat & SCSI_BUS_RESET) != 0) {
129639225Sgibbs			ahareset(aha, /*hardreset*/FALSE);
129739225Sgibbs		}
129839225Sgibbs	}
129939225Sgibbs}
130039225Sgibbs
130139225Sgibbsstatic void
130241047Sgibbsahadone(struct aha_softc *aha, struct aha_ccb *accb, aha_mbi_comp_code_t comp_code)
130339225Sgibbs{
130439225Sgibbs	union  ccb	  *ccb;
130539225Sgibbs	struct ccb_scsiio *csio;
130639225Sgibbs
130741047Sgibbs	ccb = accb->ccb;
130841047Sgibbs	csio = &accb->ccb->csio;
130939225Sgibbs
131041047Sgibbs	if ((accb->flags & ACCB_ACTIVE) == 0) {
131141047Sgibbs		printf("%s: ahadone - Attempt to free non-active ACCB %p\n",
131241047Sgibbs		       aha_name(aha), (void *)accb);
131339225Sgibbs		return;
131439225Sgibbs	}
131539225Sgibbs
131639225Sgibbs	if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
131739225Sgibbs		bus_dmasync_op_t op;
131839225Sgibbs
131939225Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
132039225Sgibbs			op = BUS_DMASYNC_POSTREAD;
132139225Sgibbs		else
132239225Sgibbs			op = BUS_DMASYNC_POSTWRITE;
132341047Sgibbs		bus_dmamap_sync(aha->buffer_dmat, accb->dmamap, op);
132441047Sgibbs		bus_dmamap_unload(aha->buffer_dmat, accb->dmamap);
132539225Sgibbs	}
132639225Sgibbs
132741047Sgibbs	if (accb == aha->recovery_accb) {
132839225Sgibbs		/*
132941047Sgibbs		 * The recovery ACCB does not have a CCB associated
133039225Sgibbs		 * with it, so short circuit the normal error handling.
133139225Sgibbs		 * We now traverse our list of pending CCBs and process
133239225Sgibbs		 * any that were terminated by the recovery CCBs action.
133339225Sgibbs		 * We also reinstate timeouts for all remaining, pending,
133439225Sgibbs		 * CCBs.
133539225Sgibbs		 */
133639225Sgibbs		struct cam_path *path;
133739225Sgibbs		struct ccb_hdr *ccb_h;
133839225Sgibbs		cam_status error;
133939225Sgibbs
134039225Sgibbs		/* Notify all clients that a BDR occured */
134139225Sgibbs		error = xpt_create_path(&path, /*periph*/NULL,
134239225Sgibbs					cam_sim_path(aha->sim),
134341047Sgibbs					accb->hccb.target,
134439225Sgibbs					CAM_LUN_WILDCARD);
134539225Sgibbs
134639225Sgibbs		if (error == CAM_REQ_CMP)
134739225Sgibbs			xpt_async(AC_SENT_BDR, path, NULL);
134839225Sgibbs
134939225Sgibbs		ccb_h = LIST_FIRST(&aha->pending_ccbs);
135039225Sgibbs		while (ccb_h != NULL) {
135141047Sgibbs			struct aha_ccb *pending_accb;
135239225Sgibbs
135341047Sgibbs			pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr;
135441047Sgibbs			if (pending_accb->hccb.target == accb->hccb.target) {
135541047Sgibbs				pending_accb->hccb.ahastat = AHASTAT_HA_BDR;
135639225Sgibbs				ccb_h = LIST_NEXT(ccb_h, sim_links.le);
135741047Sgibbs				ahadone(aha, pending_accb, AMBI_ERROR);
135839225Sgibbs			} else {
135939225Sgibbs				ccb_h->timeout_ch =
136041047Sgibbs				    timeout(ahatimeout, (caddr_t)pending_accb,
136139225Sgibbs					    (ccb_h->timeout * hz) / 1000);
136239225Sgibbs				ccb_h = LIST_NEXT(ccb_h, sim_links.le);
136339225Sgibbs			}
136439225Sgibbs		}
136539225Sgibbs		printf("%s: No longer in timeout\n", aha_name(aha));
136639225Sgibbs		return;
136739225Sgibbs	}
136839225Sgibbs
136941047Sgibbs	untimeout(ahatimeout, accb, ccb->ccb_h.timeout_ch);
137039225Sgibbs
137139225Sgibbs	switch (comp_code) {
137241047Sgibbs	case AMBI_FREE:
137339225Sgibbs		printf("%s: ahadone - CCB completed with free status!\n",
137439225Sgibbs		       aha_name(aha));
137539225Sgibbs		break;
137641047Sgibbs	case AMBI_NOT_FOUND:
137739225Sgibbs		printf("%s: ahadone - CCB Abort failed to find CCB\n",
137839225Sgibbs		       aha_name(aha));
137939225Sgibbs		break;
138041047Sgibbs	case AMBI_ABORT:
138141047Sgibbs	case AMBI_ERROR:
138239225Sgibbs		/* An error occured */
138342887Simp		if (accb->hccb.opcode < INITIATOR_CCB_WRESID)
138442887Simp			csio->resid = 0;
138542887Simp		else
138642887Simp			csio->resid = aha_a24tou(accb->hccb.data_len);
138741047Sgibbs		switch(accb->hccb.ahastat) {
138839225Sgibbs		case AHASTAT_DATARUN_ERROR:
138942013Sgibbs		{
139042013Sgibbs			if (csio->resid <= 0) {
139139225Sgibbs				csio->ccb_h.status = CAM_DATA_RUN_ERR;
139239225Sgibbs				break;
139339225Sgibbs			}
139439225Sgibbs			/* FALLTHROUGH */
139542013Sgibbs		}
139639225Sgibbs		case AHASTAT_NOERROR:
139741047Sgibbs			csio->scsi_status = accb->hccb.sdstat;
139839225Sgibbs			csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
139939225Sgibbs			switch(csio->scsi_status) {
140039225Sgibbs			case SCSI_STATUS_CHECK_COND:
140139225Sgibbs			case SCSI_STATUS_CMD_TERMINATED:
140239225Sgibbs				csio->ccb_h.status |= CAM_AUTOSNS_VALID;
140339225Sgibbs				/*
140439225Sgibbs				 * The aha writes the sense data at different
140539225Sgibbs				 * offsets based on the scsi cmd len
140639225Sgibbs				 */
140741047Sgibbs				bcopy((caddr_t) &accb->hccb.scsi_cdb +
140841047Sgibbs					accb->hccb.cmd_len,
140939225Sgibbs					(caddr_t) &csio->sense_data,
141041047Sgibbs					accb->hccb.sense_len);
141139225Sgibbs				break;
141239225Sgibbs			default:
141339225Sgibbs				break;
141439225Sgibbs			case SCSI_STATUS_OK:
141539225Sgibbs				csio->ccb_h.status = CAM_REQ_CMP;
141639225Sgibbs				break;
141739225Sgibbs			}
141839225Sgibbs			break;
141939225Sgibbs		case AHASTAT_SELTIMEOUT:
142039225Sgibbs			csio->ccb_h.status = CAM_SEL_TIMEOUT;
142139225Sgibbs			break;
142239225Sgibbs		case AHASTAT_UNEXPECTED_BUSFREE:
142339225Sgibbs			csio->ccb_h.status = CAM_UNEXP_BUSFREE;
142439225Sgibbs			break;
142539225Sgibbs		case AHASTAT_INVALID_PHASE:
142639225Sgibbs			csio->ccb_h.status = CAM_SEQUENCE_FAIL;
142739225Sgibbs			break;
142839225Sgibbs		case AHASTAT_INVALID_ACTION_CODE:
142939225Sgibbs			panic("%s: Inavlid Action code", aha_name(aha));
143039225Sgibbs			break;
143139225Sgibbs		case AHASTAT_INVALID_OPCODE:
143242887Simp			if (accb->hccb.opcode < INITIATOR_CCB_WRESID)
143342887Simp				panic("%s: Invalid CCB Opcode %x hccb = %p",
143442887Simp					aha_name(aha), accb->hccb.opcode,
143542887Simp					&accb->hccb);
143642887Simp			printf("%s: AHA-1540A detected, compensating\n",
143742887Simp				aha_name(aha));
143842887Simp			aha->ccb_sg_opcode = INITIATOR_SG_CCB;
143942887Simp			aha->ccb_ccb_opcode = INITIATOR_CCB;
144042887Simp			xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
144142887Simp			csio->ccb_h.status = CAM_REQUEUE_REQ;
144239225Sgibbs			break;
144339225Sgibbs		case AHASTAT_LINKED_CCB_LUN_MISMATCH:
144439225Sgibbs			/* We don't even support linked commands... */
144539225Sgibbs			panic("%s: Linked CCB Lun Mismatch", aha_name(aha));
144639225Sgibbs			break;
144739225Sgibbs		case AHASTAT_INVALID_CCB_OR_SG_PARAM:
144839225Sgibbs			panic("%s: Invalid CCB or SG list", aha_name(aha));
144939225Sgibbs			break;
145039225Sgibbs		case AHASTAT_HA_SCSI_BUS_RESET:
145139225Sgibbs			if ((csio->ccb_h.status & CAM_STATUS_MASK)
145242887Simp			    != CAM_CMD_TIMEOUT)
145339225Sgibbs				csio->ccb_h.status = CAM_SCSI_BUS_RESET;
145439225Sgibbs			break;
145539225Sgibbs		case AHASTAT_HA_BDR:
145641047Sgibbs			if ((accb->flags & ACCB_DEVICE_RESET) == 0)
145739225Sgibbs				csio->ccb_h.status = CAM_BDR_SENT;
145839225Sgibbs			else
145939225Sgibbs				csio->ccb_h.status = CAM_CMD_TIMEOUT;
146039225Sgibbs			break;
146139225Sgibbs		}
146239225Sgibbs		if (csio->ccb_h.status != CAM_REQ_CMP) {
146339225Sgibbs			xpt_freeze_devq(csio->ccb_h.path, /*count*/1);
146439225Sgibbs			csio->ccb_h.status |= CAM_DEV_QFRZN;
146539225Sgibbs		}
146641047Sgibbs		if ((accb->flags & ACCB_RELEASE_SIMQ) != 0)
146739225Sgibbs			ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
146841047Sgibbs		ahafreeccb(aha, accb);
146939225Sgibbs		xpt_done(ccb);
147039225Sgibbs		break;
147141047Sgibbs	case AMBI_OK:
147239225Sgibbs		/* All completed without incident */
147339225Sgibbs		/* XXX DO WE NEED TO COPY SENSE BYTES HERE???? XXX */
147442887Simp		/* I don't think so since it works???? */
147539225Sgibbs		ccb->ccb_h.status |= CAM_REQ_CMP;
147641047Sgibbs		if ((accb->flags & ACCB_RELEASE_SIMQ) != 0)
147739225Sgibbs			ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
147841047Sgibbs		ahafreeccb(aha, accb);
147939225Sgibbs		xpt_done(ccb);
148039225Sgibbs		break;
148139225Sgibbs	}
148239225Sgibbs}
148339225Sgibbs
148439225Sgibbsstatic int
148539225Sgibbsahareset(struct aha_softc* aha, int hard_reset)
148639225Sgibbs{
148739225Sgibbs	struct	 ccb_hdr *ccb_h;
148839225Sgibbs	u_int	 status;
148939225Sgibbs	u_int	 timeout;
149039225Sgibbs	u_int8_t reset_type;
149139225Sgibbs
149239225Sgibbs	if (hard_reset != 0)
149339225Sgibbs		reset_type = HARD_RESET;
149439225Sgibbs	else
149539225Sgibbs		reset_type = SOFT_RESET;
149639225Sgibbs	aha_outb(aha, CONTROL_REG, reset_type);
149739225Sgibbs
149839225Sgibbs	/* Wait 5sec. for Diagnostic start */
149939225Sgibbs	timeout = 5 * 10000;
150039225Sgibbs	while (--timeout) {
150139225Sgibbs		status = aha_inb(aha, STATUS_REG);
150239225Sgibbs		if ((status & DIAG_ACTIVE) != 0)
150339225Sgibbs			break;
150439225Sgibbs		DELAY(100);
150539225Sgibbs	}
150639225Sgibbs	if (timeout == 0) {
150739881Simp		PRVERB(("%s: ahareset - Diagnostic Active failed to "
150839881Simp			"assert. status = 0x%x\n", aha_name(aha),
150939881Simp			status));
151039225Sgibbs		return (ETIMEDOUT);
151139225Sgibbs	}
151239225Sgibbs
151339225Sgibbs	/* Wait 10sec. for Diagnostic end */
151439225Sgibbs	timeout = 10 * 10000;
151539225Sgibbs	while (--timeout) {
151639225Sgibbs		status = aha_inb(aha, STATUS_REG);
151739225Sgibbs		if ((status & DIAG_ACTIVE) == 0)
151839225Sgibbs			break;
151939225Sgibbs		DELAY(100);
152039225Sgibbs	}
152139225Sgibbs	if (timeout == 0) {
152239225Sgibbs		panic("%s: ahareset - Diagnostic Active failed to drop. "
152339225Sgibbs		       "status = 0x%x\n", aha_name(aha), status);
152439225Sgibbs		return (ETIMEDOUT);
152539225Sgibbs	}
152639225Sgibbs
152739225Sgibbs	/* Wait for the host adapter to become ready or report a failure */
152839225Sgibbs	timeout = 10000;
152939225Sgibbs	while (--timeout) {
153039225Sgibbs		status = aha_inb(aha, STATUS_REG);
153139225Sgibbs		if ((status & (DIAG_FAIL|HA_READY|DATAIN_REG_READY)) != 0)
153239225Sgibbs			break;
153339225Sgibbs		DELAY(100);
153439225Sgibbs	}
153539225Sgibbs	if (timeout == 0) {
153639225Sgibbs		printf("%s: ahareset - Host adapter failed to come ready. "
153739225Sgibbs		       "status = 0x%x\n", aha_name(aha), status);
153839225Sgibbs		return (ETIMEDOUT);
153939225Sgibbs	}
154039225Sgibbs
154139225Sgibbs	/* If the diagnostics failed, tell the user */
154239225Sgibbs	if ((status & DIAG_FAIL) != 0
154339225Sgibbs	 || (status & HA_READY) == 0) {
154439225Sgibbs		printf("%s: ahareset - Adapter failed diagnostics\n",
154539225Sgibbs		       aha_name(aha));
154639225Sgibbs
154739225Sgibbs		if ((status & DATAIN_REG_READY) != 0)
154839324Sgibbs			printf("%s: ahareset - Host Adapter Error "
154939324Sgibbs			       "code = 0x%x\n", aha_name(aha),
155039225Sgibbs			       aha_inb(aha, DATAIN_REG));
155139225Sgibbs		return (ENXIO);
155239225Sgibbs	}
155339225Sgibbs
155439225Sgibbs	/* If we've allocated mailboxes, initialize them */
155539225Sgibbs	if (aha->init_level > 4)
155639225Sgibbs		ahainitmboxes(aha);
155739225Sgibbs
155839225Sgibbs	/* If we've attached to the XPT, tell it about the event */
155939225Sgibbs	if (aha->path != NULL)
156039225Sgibbs		xpt_async(AC_BUS_RESET, aha->path, NULL);
156139225Sgibbs
156239225Sgibbs	/*
156339225Sgibbs	 * Perform completion processing for all outstanding CCBs.
156439225Sgibbs	 */
156539225Sgibbs	while ((ccb_h = LIST_FIRST(&aha->pending_ccbs)) != NULL) {
156641047Sgibbs		struct aha_ccb *pending_accb;
156739225Sgibbs
156841047Sgibbs		pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr;
156941047Sgibbs		pending_accb->hccb.ahastat = AHASTAT_HA_SCSI_BUS_RESET;
157041047Sgibbs		ahadone(aha, pending_accb, AMBI_ERROR);
157139225Sgibbs	}
157239225Sgibbs
157339225Sgibbs	return (0);
157439225Sgibbs}
157539225Sgibbs
157639225Sgibbs/*
157739225Sgibbs * Send a command to the adapter.
157839225Sgibbs */
157939225Sgibbsint
158039225Sgibbsaha_cmd(struct aha_softc *aha, aha_op_t opcode, u_int8_t *params,
158147506Sgibbs	u_int param_len, u_int8_t *reply_data, u_int reply_len,
158247506Sgibbs	u_int cmd_timeout)
158339225Sgibbs{
158439225Sgibbs	u_int	timeout;
158539225Sgibbs	u_int	status;
158647506Sgibbs	u_int	saved_status;
158739225Sgibbs	u_int	intstat;
158839225Sgibbs	u_int	reply_buf_size;
158939225Sgibbs	int	s;
159041709Sgibbs	int	cmd_complete;
159147506Sgibbs	int	error;
159239225Sgibbs
159339225Sgibbs	/* No data returned to start */
159439225Sgibbs	reply_buf_size = reply_len;
159539225Sgibbs	reply_len = 0;
159639225Sgibbs	intstat = 0;
159741709Sgibbs	cmd_complete = 0;
159847506Sgibbs	saved_status = 0;
159947506Sgibbs	error = 0;
160039225Sgibbs
160147506Sgibbs	/*
160247506Sgibbs	 * All commands except for the "start mailbox" and the "enable
160347506Sgibbs	 * outgoing mailbox read interrupt" commands cannot be issued
160447506Sgibbs	 * while there are pending transactions.  Freeze our SIMQ
160547506Sgibbs	 * and wait for all completions to occur if necessary.
160647506Sgibbs	 */
160747506Sgibbs	timeout = 100000;
160847506Sgibbs	s = splcam();
160947506Sgibbs	while (LIST_FIRST(&aha->pending_ccbs) != NULL && --timeout) {
161047506Sgibbs		/* Fire the interrupt handler in case interrupts are blocked */
161147506Sgibbs		aha_intr(aha);
161247506Sgibbs		splx(s);
161347506Sgibbs		DELAY(100);
161447506Sgibbs		s = splcam();
161547506Sgibbs	}
161647506Sgibbs	splx(s);
161747506Sgibbs
161847506Sgibbs	if (timeout == 0) {
161947506Sgibbs		printf("%s: aha_cmd: Timeout waiting for adapter idle\n",
162047506Sgibbs		       aha_name(aha));
162147506Sgibbs		return (ETIMEDOUT);
162247506Sgibbs	}
162339225Sgibbs	aha->command_cmp = 0;
162439225Sgibbs	/*
162547506Sgibbs	 * Wait up to 10 sec. for the adapter to become
162639225Sgibbs	 * ready to accept commands.
162739225Sgibbs	 */
162847506Sgibbs	timeout = 100000;
162939225Sgibbs	while (--timeout) {
163039225Sgibbs
163139225Sgibbs		status = aha_inb(aha, STATUS_REG);
163239225Sgibbs		if ((status & HA_READY) != 0
163339225Sgibbs		 && (status & CMD_REG_BUSY) == 0)
163439225Sgibbs			break;
163547506Sgibbs		/*
163647506Sgibbs		 * Throw away any pending data which may be
163747506Sgibbs		 * left over from earlier commands that we
163847506Sgibbs		 * timedout on.
163947506Sgibbs		 */
164047506Sgibbs		if ((status & DATAIN_REG_READY) != 0)
164147506Sgibbs			(void)aha_inb(aha, DATAIN_REG);
164239225Sgibbs		DELAY(100);
164339225Sgibbs	}
164439225Sgibbs	if (timeout == 0) {
164539225Sgibbs		printf("%s: aha_cmd: Timeout waiting for adapter ready, "
164639225Sgibbs		       "status = 0x%x\n", aha_name(aha), status);
164739225Sgibbs		return (ETIMEDOUT);
164839225Sgibbs	}
164939225Sgibbs
165039225Sgibbs	/*
165139225Sgibbs	 * Send the opcode followed by any necessary parameter bytes.
165239225Sgibbs	 */
165339225Sgibbs	aha_outb(aha, COMMAND_REG, opcode);
165439225Sgibbs
165539225Sgibbs	/*
165639225Sgibbs	 * Wait for up to 1sec to get the parameter list sent
165739225Sgibbs	 */
165839225Sgibbs	timeout = 10000;
165939225Sgibbs	while (param_len && --timeout) {
166039225Sgibbs		DELAY(100);
166147506Sgibbs		s = splcam();
166239225Sgibbs		status = aha_inb(aha, STATUS_REG);
166339225Sgibbs		intstat = aha_inb(aha, INTSTAT_REG);
166447506Sgibbs		splx(s);
166547506Sgibbs
166639225Sgibbs		if ((intstat & (INTR_PENDING|CMD_COMPLETE))
166741709Sgibbs		 == (INTR_PENDING|CMD_COMPLETE)) {
166847506Sgibbs			saved_status = status;
166941709Sgibbs			cmd_complete = 1;
167039225Sgibbs			break;
167141709Sgibbs		}
167247506Sgibbs
167339225Sgibbs		if (aha->command_cmp != 0) {
167447506Sgibbs			saved_status = aha->latched_status;
167541709Sgibbs			cmd_complete = 1;
167639225Sgibbs			break;
167739225Sgibbs		}
167839225Sgibbs		if ((status & DATAIN_REG_READY) != 0)
167939225Sgibbs			break;
168039225Sgibbs		if ((status & CMD_REG_BUSY) == 0) {
168139225Sgibbs			aha_outb(aha, COMMAND_REG, *params++);
168239225Sgibbs			param_len--;
168347506Sgibbs			timeout = 10000;
168439225Sgibbs		}
168539225Sgibbs	}
168639225Sgibbs	if (timeout == 0) {
168739225Sgibbs		printf("%s: aha_cmd: Timeout sending parameters, "
168839225Sgibbs		       "status = 0x%x\n", aha_name(aha), status);
168947506Sgibbs		error = ETIMEDOUT;
169039225Sgibbs	}
169139225Sgibbs
169239225Sgibbs	/*
169339225Sgibbs	 * For all other commands, we wait for any output data
169439225Sgibbs	 * and the final comand completion interrupt.
169539225Sgibbs	 */
169641709Sgibbs	while (cmd_complete == 0 && --cmd_timeout) {
169739225Sgibbs
169847506Sgibbs		s = splcam();
169939225Sgibbs		status = aha_inb(aha, STATUS_REG);
170039225Sgibbs		intstat = aha_inb(aha, INTSTAT_REG);
170147506Sgibbs		splx(s);
170239225Sgibbs
170339225Sgibbs		if (aha->command_cmp != 0) {
170447506Sgibbs			cmd_complete = 1;
170547506Sgibbs			saved_status = aha->latched_status;
170647506Sgibbs		} else if ((intstat & (INTR_PENDING|CMD_COMPLETE))
170747506Sgibbs			== (INTR_PENDING|CMD_COMPLETE)) {
170847506Sgibbs			/*
170947506Sgibbs			 * Our poll (in case interrupts are blocked)
171047506Sgibbs			 * saw the CMD_COMPLETE interrupt.
171147506Sgibbs			 */
171247506Sgibbs			cmd_complete = 1;
171347506Sgibbs			saved_status = status;
171447506Sgibbs		} else if ((status & DATAIN_REG_READY) != 0) {
171539225Sgibbs			u_int8_t data;
171639225Sgibbs
171739225Sgibbs			data = aha_inb(aha, DATAIN_REG);
171839225Sgibbs			if (reply_len < reply_buf_size) {
171939225Sgibbs				*reply_data++ = data;
172039225Sgibbs			} else {
172147506Sgibbs				printf("%s: aha_cmd - Discarded reply data "
172247506Sgibbs				       "byte for opcode 0x%x\n", aha_name(aha),
172339225Sgibbs				       opcode);
172439225Sgibbs			}
172547506Sgibbs			/*
172647506Sgibbs			 * Reset timeout to ensure at least a second
172747506Sgibbs			 * between response bytes.
172847506Sgibbs			 */
172947506Sgibbs			cmd_timeout = MAX(cmd_timeout, 10000);
173039225Sgibbs			reply_len++;
173139225Sgibbs		}
173239225Sgibbs		DELAY(100);
173339225Sgibbs	}
173447506Sgibbs	if (cmd_timeout == 0) {
173539225Sgibbs		printf("%s: aha_cmd: Timeout waiting for reply data and "
173639225Sgibbs		       "command complete.\n%s: status = 0x%x, intstat = 0x%x, "
173739225Sgibbs		       "reply_len = %d\n", aha_name(aha), aha_name(aha), status,
173839225Sgibbs		       intstat, reply_len);
173939225Sgibbs		return (ETIMEDOUT);
174039225Sgibbs	}
174139225Sgibbs
174239225Sgibbs	/*
174339225Sgibbs	 * Clear any pending interrupts.  Block interrupts so our
174439225Sgibbs	 * interrupt handler is not re-entered.
174539225Sgibbs	 */
174639225Sgibbs	s = splcam();
174739225Sgibbs	aha_intr(aha);
174839225Sgibbs	splx(s);
174939225Sgibbs
175047506Sgibbs	if (error != 0)
175147506Sgibbs		return (error);
175247506Sgibbs
175339225Sgibbs	/*
175439225Sgibbs	 * If the command was rejected by the controller, tell the caller.
175539225Sgibbs	 */
175647506Sgibbs	if ((saved_status & CMD_INVALID) != 0) {
175739881Simp		PRVERB(("%s: Invalid Command 0x%x\n", aha_name(aha), opcode));
175839225Sgibbs		/*
175939225Sgibbs		 * Some early adapters may not recover properly from
176039225Sgibbs		 * an invalid command.  If it appears that the controller
176139225Sgibbs		 * has wedged (i.e. status was not cleared by our interrupt
176239225Sgibbs		 * reset above), perform a soft reset.
176339225Sgibbs      		 */
176439225Sgibbs		DELAY(1000);
176539225Sgibbs		status = aha_inb(aha, STATUS_REG);
176639225Sgibbs		if ((status & (CMD_INVALID|STATUS_REG_RSVD|DATAIN_REG_READY|
176739225Sgibbs			      CMD_REG_BUSY|DIAG_FAIL|DIAG_ACTIVE)) != 0
176839225Sgibbs		 || (status & (HA_READY|INIT_REQUIRED))
176939225Sgibbs		  != (HA_READY|INIT_REQUIRED)) {
177039852Simp			ahareset(aha, /*hard_reset*/FALSE);
177139225Sgibbs		}
177239225Sgibbs		return (EINVAL);
177339225Sgibbs	}
177439225Sgibbs
177539225Sgibbs	if (param_len > 0) {
177639225Sgibbs		/* The controller did not accept the full argument list */
177739225Sgibbs	 	return (E2BIG);
177839225Sgibbs	}
177939225Sgibbs
178039225Sgibbs	if (reply_len != reply_buf_size) {
178139225Sgibbs		/* Too much or too little data received */
178239225Sgibbs		return (EMSGSIZE);
178339225Sgibbs	}
178439225Sgibbs
178539225Sgibbs	/* We were successful */
178639225Sgibbs	return (0);
178739225Sgibbs}
178839225Sgibbs
178939225Sgibbsstatic int
179039225Sgibbsahainitmboxes(struct aha_softc *aha)
179139225Sgibbs{
179239225Sgibbs	int error;
179339225Sgibbs	init_24b_mbox_params_t init_mbox;
179439225Sgibbs
179539225Sgibbs	bzero(aha->in_boxes, sizeof(aha_mbox_in_t) * aha->num_boxes);
179639225Sgibbs	bzero(aha->out_boxes, sizeof(aha_mbox_out_t) * aha->num_boxes);
179739225Sgibbs	aha->cur_inbox = aha->in_boxes;
179839225Sgibbs	aha->last_inbox = aha->in_boxes + aha->num_boxes - 1;
179939225Sgibbs	aha->cur_outbox = aha->out_boxes;
180039225Sgibbs	aha->last_outbox = aha->out_boxes + aha->num_boxes - 1;
180139225Sgibbs
180239225Sgibbs	/* Tell the adapter about them */
180339225Sgibbs	init_mbox.num_mboxes = aha->num_boxes;
180439225Sgibbs	ahautoa24(aha->mailbox_physbase, init_mbox.base_addr);
180541047Sgibbs	error = aha_cmd(aha, AOP_INITIALIZE_MBOX, (u_int8_t *)&init_mbox,
180639225Sgibbs		       /*parmlen*/sizeof(init_mbox), /*reply_buf*/NULL,
180739225Sgibbs		       /*reply_len*/0, DEFAULT_CMD_TIMEOUT);
180839225Sgibbs
180939225Sgibbs	if (error != 0)
181039225Sgibbs		printf("ahainitmboxes: Initialization command failed\n");
181139225Sgibbs	return (error);
181239225Sgibbs}
181339225Sgibbs
181439225Sgibbs/*
181539225Sgibbs * Update the XPT's idea of the negotiated transfer
181639225Sgibbs * parameters for a particular target.
181739225Sgibbs */
181839225Sgibbsstatic void
181939225Sgibbsahafetchtransinfo(struct aha_softc *aha, struct ccb_trans_settings* cts)
182039225Sgibbs{
182139225Sgibbs	setup_data_t	setup_info;
182239225Sgibbs	u_int		target;
182339225Sgibbs	u_int		targ_offset;
182439225Sgibbs	u_int		sync_period;
182539225Sgibbs	int		error;
182639225Sgibbs	u_int8_t	param;
182739225Sgibbs	targ_syncinfo_t	sync_info;
182839225Sgibbs
182939225Sgibbs	target = cts->ccb_h.target_id;
183039225Sgibbs	targ_offset = (target & 0x7);
183139225Sgibbs
183239225Sgibbs	/*
183347208Simp	 * Inquire Setup Information.  This command retreives
183447506Sgibbs	 * the sync info for older models.
183539225Sgibbs	 */
183639225Sgibbs	param = sizeof(setup_info);
183741047Sgibbs	error = aha_cmd(aha, AOP_INQUIRE_SETUP_INFO, &param, /*paramlen*/1,
183839225Sgibbs		       (u_int8_t*)&setup_info, sizeof(setup_info),
183939225Sgibbs		       DEFAULT_CMD_TIMEOUT);
184039225Sgibbs
184139225Sgibbs	if (error != 0) {
184247506Sgibbs		printf("%s: ahafetchtransinfo - Inquire Setup Info Failed %d\n",
184347506Sgibbs		       aha_name(aha), error);
184439225Sgibbs		return;
184539225Sgibbs	}
184639225Sgibbs
184739225Sgibbs	sync_info = setup_info.syncinfo[targ_offset];
184839225Sgibbs
184939225Sgibbs	if (sync_info.sync == 0)
185039225Sgibbs		cts->sync_offset = 0;
185139225Sgibbs	else
185239225Sgibbs		cts->sync_offset = sync_info.offset;
185339225Sgibbs
185439225Sgibbs	cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
185539225Sgibbs
185647506Sgibbs	if (aha->boardid >= BOARD_1542CF)
185747506Sgibbs		sync_period = 1000;
185847506Sgibbs	else
185947506Sgibbs		sync_period = 2000;
186047506Sgibbs	sync_period += 500 * sync_info.period;
186139225Sgibbs
186239225Sgibbs	/* Convert ns value to standard SCSI sync rate */
186339225Sgibbs	if (cts->sync_offset != 0)
186439225Sgibbs		cts->sync_period = scsi_calc_syncparam(sync_period);
186539225Sgibbs	else
186639225Sgibbs		cts->sync_period = 0;
186739225Sgibbs
186839225Sgibbs	cts->valid = CCB_TRANS_SYNC_RATE_VALID
186939225Sgibbs		   | CCB_TRANS_SYNC_OFFSET_VALID
187039225Sgibbs		   | CCB_TRANS_BUS_WIDTH_VALID;
187139225Sgibbs        xpt_async(AC_TRANSFER_NEG, cts->ccb_h.path, cts);
187239225Sgibbs}
187339225Sgibbs
187439225Sgibbsstatic void
187539225Sgibbsahamapmboxes(void *arg, bus_dma_segment_t *segs, int nseg, int error)
187639225Sgibbs{
187739225Sgibbs	struct aha_softc* aha;
187839225Sgibbs
187939225Sgibbs	aha = (struct aha_softc*)arg;
188039225Sgibbs	aha->mailbox_physbase = segs->ds_addr;
188139225Sgibbs}
188239225Sgibbs
188339225Sgibbsstatic void
188439225Sgibbsahamapccbs(void *arg, bus_dma_segment_t *segs, int nseg, int error)
188539225Sgibbs{
188639225Sgibbs	struct aha_softc* aha;
188739225Sgibbs
188839225Sgibbs	aha = (struct aha_softc*)arg;
188939225Sgibbs	aha->aha_ccb_physbase = segs->ds_addr;
189039225Sgibbs}
189139225Sgibbs
189239225Sgibbsstatic void
189339225Sgibbsahamapsgs(void *arg, bus_dma_segment_t *segs, int nseg, int error)
189439225Sgibbs{
189539225Sgibbs
189639225Sgibbs	struct aha_softc* aha;
189739225Sgibbs
189839225Sgibbs	aha = (struct aha_softc*)arg;
189939225Sgibbs	SLIST_FIRST(&aha->sg_maps)->sg_physaddr = segs->ds_addr;
190039225Sgibbs}
190139225Sgibbs
190239225Sgibbsstatic void
190339225Sgibbsahapoll(struct cam_sim *sim)
190439225Sgibbs{
190540132Sgibbs	aha_intr(cam_sim_softc(sim));
190639225Sgibbs}
190739225Sgibbs
190845575Seivindstatic void
190939225Sgibbsahatimeout(void *arg)
191039225Sgibbs{
191141047Sgibbs	struct aha_ccb	*accb;
191239225Sgibbs	union  ccb	*ccb;
191339225Sgibbs	struct aha_softc *aha;
191439225Sgibbs	int		 s;
191539225Sgibbs	u_int32_t	paddr;
191639225Sgibbs
191741047Sgibbs	accb = (struct aha_ccb *)arg;
191841047Sgibbs	ccb = accb->ccb;
191939225Sgibbs	aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr;
192039225Sgibbs	xpt_print_path(ccb->ccb_h.path);
192141047Sgibbs	printf("CCB %p - timed out\n", (void *)accb);
192239225Sgibbs
192339225Sgibbs	s = splcam();
192439225Sgibbs
192541047Sgibbs	if ((accb->flags & ACCB_ACTIVE) == 0) {
192639225Sgibbs		xpt_print_path(ccb->ccb_h.path);
192739390Sgibbs		printf("CCB %p - timed out CCB already completed\n",
192841047Sgibbs		       (void *)accb);
192939225Sgibbs		splx(s);
193039225Sgibbs		return;
193139225Sgibbs	}
193239225Sgibbs
193339225Sgibbs	/*
193439225Sgibbs	 * In order to simplify the recovery process, we ask the XPT
193539225Sgibbs	 * layer to halt the queue of new transactions and we traverse
193639225Sgibbs	 * the list of pending CCBs and remove their timeouts. This
193739225Sgibbs	 * means that the driver attempts to clear only one error
193839225Sgibbs	 * condition at a time.  In general, timeouts that occur
193939225Sgibbs	 * close together are related anyway, so there is no benefit
194039225Sgibbs	 * in attempting to handle errors in parrallel.  Timeouts will
194139225Sgibbs	 * be reinstated when the recovery process ends.
194239225Sgibbs	 */
194341047Sgibbs	if ((accb->flags & ACCB_DEVICE_RESET) == 0) {
194439225Sgibbs		struct ccb_hdr *ccb_h;
194539225Sgibbs
194641047Sgibbs		if ((accb->flags & ACCB_RELEASE_SIMQ) == 0) {
194739225Sgibbs			xpt_freeze_simq(aha->sim, /*count*/1);
194841047Sgibbs			accb->flags |= ACCB_RELEASE_SIMQ;
194939225Sgibbs		}
195039225Sgibbs
195139225Sgibbs		ccb_h = LIST_FIRST(&aha->pending_ccbs);
195239225Sgibbs		while (ccb_h != NULL) {
195341047Sgibbs			struct aha_ccb *pending_accb;
195439225Sgibbs
195541047Sgibbs			pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr;
195641047Sgibbs			untimeout(ahatimeout, pending_accb, ccb_h->timeout_ch);
195739225Sgibbs			ccb_h = LIST_NEXT(ccb_h, sim_links.le);
195839225Sgibbs		}
195939225Sgibbs	}
196039225Sgibbs
196141047Sgibbs	if ((accb->flags & ACCB_DEVICE_RESET) != 0
196241047Sgibbs	 || aha->cur_outbox->action_code != AMBO_FREE) {
196339225Sgibbs		/*
196439225Sgibbs		 * Try a full host adapter/SCSI bus reset.
196539225Sgibbs		 * We do this only if we have already attempted
196639225Sgibbs		 * to clear the condition with a BDR, or we cannot
196739225Sgibbs		 * attempt a BDR for lack of mailbox resources.
196839225Sgibbs		 */
196939225Sgibbs		ccb->ccb_h.status = CAM_CMD_TIMEOUT;
197039225Sgibbs		ahareset(aha, /*hardreset*/TRUE);
197139225Sgibbs		printf("%s: No longer in timeout\n", aha_name(aha));
197239225Sgibbs	} else {
197339225Sgibbs		/*
197439225Sgibbs		 * Send a Bus Device Reset message:
197539225Sgibbs		 * The target that is holding up the bus may not
197639225Sgibbs		 * be the same as the one that triggered this timeout
197739225Sgibbs		 * (different commands have different timeout lengths),
197839225Sgibbs		 * but we have no way of determining this from our
197939225Sgibbs		 * timeout handler.  Our strategy here is to queue a
198039225Sgibbs		 * BDR message to the target of the timed out command.
198139225Sgibbs		 * If this fails, we'll get another timeout 2 seconds
198239225Sgibbs		 * later which will attempt a bus reset.
198339225Sgibbs		 */
198441047Sgibbs		accb->flags |= ACCB_DEVICE_RESET;
198541047Sgibbs		ccb->ccb_h.timeout_ch = timeout(ahatimeout, (caddr_t)accb, 2 * hz);
198641047Sgibbs		aha->recovery_accb->hccb.opcode = INITIATOR_BUS_DEV_RESET;
198739225Sgibbs
198839225Sgibbs		/* No Data Transfer */
198941047Sgibbs		aha->recovery_accb->hccb.datain = TRUE;
199041047Sgibbs		aha->recovery_accb->hccb.dataout = TRUE;
199141047Sgibbs		aha->recovery_accb->hccb.ahastat = 0;
199241047Sgibbs		aha->recovery_accb->hccb.sdstat = 0;
199341047Sgibbs		aha->recovery_accb->hccb.target = ccb->ccb_h.target_id;
199439225Sgibbs
199539225Sgibbs		/* Tell the adapter about this command */
199641047Sgibbs		paddr = ahaccbvtop(aha, aha->recovery_accb);
199739225Sgibbs		ahautoa24(paddr, aha->cur_outbox->ccb_addr);
199841047Sgibbs		aha->cur_outbox->action_code = AMBO_START;
199941047Sgibbs		aha_outb(aha, COMMAND_REG, AOP_START_MBOX);
200039225Sgibbs		ahanextoutbox(aha);
200139225Sgibbs	}
200239225Sgibbs
200339225Sgibbs	splx(s);
200439225Sgibbs}
2005