aha.c revision 39324
11592Srgrimes/*
21592Srgrimes * Generic register and struct definitions for the Adaptech 154x/164x
31592Srgrimes * SCSI host adapters. Product specific probe and attach routines can
41592Srgrimes * be found in:
51592Srgrimes *      <fill in list here> XXX
61592Srgrimes *
71592Srgrimes * Derived from bt.c written by:
81592Srgrimes *
91592Srgrimes * Copyright (c) 1998 Justin T. Gibbs.
101592Srgrimes * All rights reserved.
111592Srgrimes *
121592Srgrimes * Redistribution and use in source and binary forms, with or without
131592Srgrimes * modification, are permitted provided that the following conditions
141592Srgrimes * are met:
151592Srgrimes * 1. Redistributions of source code must retain the above copyright
161592Srgrimes *    notice, this list of conditions, and the following disclaimer,
171592Srgrimes *    without modification, immediately at the beginning of the file.
181592Srgrimes * 2. The name of the author may not be used to endorse or promote products
191592Srgrimes *    derived from this software without specific prior written permission.
201592Srgrimes *
211592Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
221592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241592Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
251592Srgrimes * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291592Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311592Srgrimes * SUCH DAMAGE.
321592Srgrimes *
331592Srgrimes *      $Id: aha.c,v 1.1 1998/09/15 07:39:52 gibbs Exp $
3417478Smarkm */
351592Srgrimes
361592Srgrimes#include <sys/param.h>
371592Srgrimes#include <sys/systm.h>
381592Srgrimes#include <sys/malloc.h>
391592Srgrimes#include <sys/buf.h>
4017478Smarkm#include <sys/kernel.h>
411592Srgrimes#include <sys/sysctl.h>
4231329Scharnier
4317478Smarkm#include <machine/bus_pio.h>
441592Srgrimes#include <machine/bus.h>
4531329Scharnier#include <machine/clock.h>
4631329Scharnier
4750476Speter#include <cam/cam.h>
481592Srgrimes#include <cam/cam_ccb.h>
491592Srgrimes#include <cam/cam_sim.h>
501592Srgrimes#include <cam/cam_xpt_sim.h>
511592Srgrimes#include <cam/cam_debug.h>
521592Srgrimes
531592Srgrimes#include <cam/scsi/scsi_message.h>
541592Srgrimes
5566907Swollman#include <vm/vm.h>
561592Srgrimes#include <vm/pmap.h>
5766907Swollman
5866907Swollman#include <dev/aha/ahareg.h>
591592Srgrimes
601592Srgrimesstruct aha_softc *aha_softcs[NAHA];
611592Srgrimes
621592Srgrimes#define MIN(a, b) ((a) < (b) ? (a) : (b))
631592Srgrimes
648240Swollman/* MailBox Management functions */
651592Srgrimesstatic __inline void	ahanextinbox(struct aha_softc *aha);
661592Srgrimesstatic __inline void	ahanextoutbox(struct aha_softc *aha);
671592Srgrimes
681592Srgrimesstatic __inline void
691592Srgrimesahanextinbox(struct aha_softc *aha)
701592Srgrimes{
711592Srgrimes	if (aha->cur_inbox == aha->last_inbox)
721592Srgrimes		aha->cur_inbox = aha->in_boxes;
731592Srgrimes	else
741592Srgrimes		aha->cur_inbox++;
751592Srgrimes}
761592Srgrimes
771592Srgrimesstatic __inline void
781592Srgrimesahanextoutbox(struct aha_softc *aha)
791592Srgrimes{
8025187Sdavidn	if (aha->cur_outbox == aha->last_outbox)
8179469Smarkm		aha->cur_outbox = aha->out_boxes;
8279469Smarkm	else
8379469Smarkm		aha->cur_outbox++;
841592Srgrimes}
851592Srgrimes
861592Srgrimes#define ahautoa24(u,s3)			\
871592Srgrimes	(s3)[0] = ((u) >> 16) & 0xff;	\
881592Srgrimes	(s3)[1] = ((u) >> 8) & 0xff;	\
891592Srgrimes	(s3)[2] = (u) & 0xff;
901592Srgrimes
911592Srgrimes#define aha_a24tou(s3) \
9213139Speter	(((s3)[0] << 16) | ((s3)[1] << 8) | (s3)[2])
9325101Sdavidn
9425101Sdavidn/* CCB Mangement functions */
9525101Sdavidnstatic __inline u_int32_t		ahaccbvtop(struct aha_softc *aha,
961592Srgrimes						  struct aha_ccb *bccb);
9774874Smarkmstatic __inline struct aha_ccb*		ahaccbptov(struct aha_softc *aha,
9851433Smarkm						  u_int32_t ccb_addr);
9951433Smarkm
10051433Smarkmstatic __inline u_int32_t
1011592Srgrimesahaccbvtop(struct aha_softc *aha, struct aha_ccb *bccb)
1021592Srgrimes{
1031592Srgrimes	return (aha->aha_ccb_physbase
1041592Srgrimes	      + (u_int32_t)((caddr_t)bccb - (caddr_t)aha->aha_ccb_array));
1051592Srgrimes}
1061592Srgrimesstatic __inline struct aha_ccb *
1071592Srgrimesahaccbptov(struct aha_softc *aha, u_int32_t ccb_addr)
1081592Srgrimes{
1091592Srgrimes	return (aha->aha_ccb_array +
11025165Sdavidn	      + ((struct aha_ccb*)ccb_addr-(struct aha_ccb*)aha->aha_ccb_physbase));
11125165Sdavidn}
1121592Srgrimes
11356668Sshinstatic struct aha_ccb*	ahagetccb(struct aha_softc *aha);
11456668Sshinstatic __inline void	ahafreeccb(struct aha_softc *aha, struct aha_ccb *bccb);
11556668Sshinstatic void		ahaallocccbs(struct aha_softc *aha);
11656668Sshinstatic bus_dmamap_callback_t ahaexecuteccb;
11756668Sshinstatic void		ahadone(struct aha_softc *aha, struct aha_ccb *bccb,
1181592Srgrimes			       aha_mbi_comp_code_t comp_code);
1191592Srgrimes
1201592Srgrimes/* Host adapter command functions */
12156668Sshinstatic int	ahareset(struct aha_softc* aha, int hard_reset);
12256668Sshin
12356668Sshin/* Initialization functions */
12456668Sshinstatic int			ahainitmboxes(struct aha_softc *aha);
12556668Sshinstatic bus_dmamap_callback_t	ahamapmboxes;
12656668Sshinstatic bus_dmamap_callback_t	ahamapccbs;
1271592Srgrimesstatic bus_dmamap_callback_t	ahamapsgs;
12815196Sdg
1291592Srgrimes/* Transfer Negotiation Functions */
1301592Srgrimesstatic void ahafetchtransinfo(struct aha_softc *aha,
1311592Srgrimes			     struct ccb_trans_settings *cts);
1321592Srgrimes
13376096Smarkm/* CAM SIM entry points */
1341592Srgrimes#define ccb_bccb_ptr spriv_ptr0
1351592Srgrimes#define ccb_aha_ptr spriv_ptr1
1361592Srgrimesstatic void	ahaaction(struct cam_sim *sim, union ccb *ccb);
1379933Spststatic void	ahapoll(struct cam_sim *sim);
13817435Spst
13920042Storstenb/* Our timeout handler */
1401592Srgrimestimeout_t ahatimeout;
14117435Spst
1426740Sguidou_long aha_unit = 0;
1436740Sguido
1441592Srgrimes/*
1451592Srgrimes * Do our own re-probe protection until a configuration
1461592Srgrimes * manager can do it for us.  This ensures that we don't
1471592Srgrimes * reprobe a card already found by the EISA or PCI probes.
1481592Srgrimes */
1491592Srgrimesstruct aha_isa_port aha_isa_ports[] =
15070102Sphk{
15170102Sphk	{ 0x330, 0 },
15282460Snik	{ 0x334, 0 },
15382796Ssheldonh	{ 0x230, 0 },
15482460Snik	{ 0x234, 0 },
1551592Srgrimes	{ 0x130, 0 },
1561592Srgrimes	{ 0x134, 0 }
1571592Srgrimes};
1581592Srgrimes
1591592Srgrimes/* Exported functions */
1601592Srgrimesstruct aha_softc *
1611592Srgrimesaha_alloc(int unit, bus_space_tag_t tag, bus_space_handle_t bsh)
1621592Srgrimes{
1631592Srgrimes	struct  aha_softc *aha;
16427650Sdavidn	int	i;
16578153Sdd
16678153Sdd	if (unit != AHA_TEMP_UNIT) {
16725283Sdavidn		if (unit >= NAHA) {
16825283Sdavidn			printf("aha: unit number (%d) too high\n", unit);
16925283Sdavidn			return NULL;
17025283Sdavidn		}
17125283Sdavidn
17257124Sshin		/*
17325283Sdavidn		 * Allocate a storage area for us
17425283Sdavidn		 */
17525283Sdavidn		if (aha_softcs[unit]) {
17625283Sdavidn			printf("aha%d: memory already allocated\n", unit);
17725283Sdavidn			return NULL;
17825283Sdavidn		}
17925283Sdavidn	}
18025283Sdavidn
18145422Sbrian	aha = malloc(sizeof(struct aha_softc), M_DEVBUF, M_NOWAIT);
1826740Sguido	if (!aha) {
18317435Spst		printf("aha%d: cannot malloc!\n", unit);
18417435Spst		return NULL;
18517435Spst	}
18617435Spst	bzero(aha, sizeof(struct aha_softc));
18774874Smarkm	SLIST_INIT(&aha->free_aha_ccbs);
18851433Smarkm	LIST_INIT(&aha->pending_ccbs);
18974874Smarkm	SLIST_INIT(&aha->sg_maps);
19079469Smarkm	aha->unit = unit;
19179469Smarkm	aha->tag = tag;
19279469Smarkm	aha->bsh = bsh;
19379469Smarkm
19417478Smarkm	if (aha->unit != AHA_TEMP_UNIT) {
19517478Smarkm		aha_softcs[unit] = aha;
19617483Sjulian	}
19717483Sjulian	return (aha);
1981592Srgrimes}
19974470Sjlemon
20074470Sjlemonvoid
20174470Sjlemonaha_free(struct aha_softc *aha)
20274470Sjlemon{
20374470Sjlemon	switch (aha->init_level) {
20474470Sjlemon	default:
20574470Sjlemon	case 8:
2061592Srgrimes	{
2071592Srgrimes		struct sg_map_node *sg_map;
2081592Srgrimes
2091592Srgrimes		while ((sg_map = SLIST_FIRST(&aha->sg_maps))!= NULL) {
2101592Srgrimes			SLIST_REMOVE_HEAD(&aha->sg_maps, links);
2111592Srgrimes			bus_dmamap_unload(aha->sg_dmat,
2121592Srgrimes					  sg_map->sg_dmamap);
2131592Srgrimes			bus_dmamem_free(aha->sg_dmat, sg_map->sg_vaddr,
2141592Srgrimes					sg_map->sg_dmamap);
2151592Srgrimes			free(sg_map, M_DEVBUF);
2161592Srgrimes		}
21713139Speter		bus_dma_tag_destroy(aha->sg_dmat);
2181592Srgrimes	}
2191592Srgrimes	case 7:
22013139Speter		bus_dmamap_unload(aha->ccb_dmat, aha->ccb_dmamap);
2211592Srgrimes	case 6:
2221592Srgrimes		bus_dmamap_destroy(aha->ccb_dmat, aha->ccb_dmamap);
2231592Srgrimes		bus_dmamem_free(aha->ccb_dmat, aha->aha_ccb_array,
2241592Srgrimes				aha->ccb_dmamap);
2251592Srgrimes	case 5:
2261592Srgrimes		bus_dma_tag_destroy(aha->ccb_dmat);
2271592Srgrimes	case 4:
2281592Srgrimes		bus_dmamap_unload(aha->mailbox_dmat, aha->mailbox_dmamap);
2291592Srgrimes	case 3:
2301592Srgrimes		bus_dmamem_free(aha->mailbox_dmat, aha->in_boxes,
2311592Srgrimes				aha->mailbox_dmamap);
2321592Srgrimes		bus_dmamap_destroy(aha->mailbox_dmat, aha->mailbox_dmamap);
2331592Srgrimes	case 2:
2341592Srgrimes		bus_dma_tag_destroy(aha->buffer_dmat);
2351592Srgrimes	case 1:
2361592Srgrimes		bus_dma_tag_destroy(aha->mailbox_dmat);
2371592Srgrimes	case 0:
2381592Srgrimes	}
2391592Srgrimes	if (aha->unit != AHA_TEMP_UNIT) {
2401592Srgrimes		aha_softcs[aha->unit] = NULL;
2411592Srgrimes	}
2421592Srgrimes	free(aha, M_DEVBUF);
24325283Sdavidn}
24425283Sdavidn
24556668Sshin/*
24625283Sdavidn * Probe the adapter and verify that the card is an Adaptec.
2471592Srgrimes */
2481592Srgrimesint
24936349Ssteveaha_probe(struct aha_softc* aha)
2501592Srgrimes{
25156668Sshin	u_int	 status;
2521592Srgrimes	u_int	 intstat;
2531592Srgrimes	int	 error;
2541592Srgrimes	u_int8_t param;
2551592Srgrimes	esetup_info_data_t esetup_info;
2561592Srgrimes
2571592Srgrimes	/*
2588240Swollman	 * See if the three I/O ports look reasonable.
2591592Srgrimes	 * Touch the minimal number of registers in the
2601592Srgrimes	 * failure case.
2611592Srgrimes	 */
26215196Sdg	status = aha_inb(aha, STATUS_REG);
26382792Sache	if ((status == 0)
2641592Srgrimes	 || (status & (DIAG_ACTIVE|CMD_REG_BUSY|
2651592Srgrimes		       STATUS_REG_RSVD|CMD_INVALID)) != 0) {
2661592Srgrimes		return (ENXIO);
2671592Srgrimes	}
2681592Srgrimes
2691592Srgrimes	intstat = aha_inb(aha, INTSTAT_REG);
2701592Srgrimes	if ((intstat & INTSTAT_REG_RSVD) != 0) {
2711592Srgrimes		printf("%s: Failed Intstat Reg Test\n", aha_name(aha));
2721592Srgrimes		return (ENXIO);
2731592Srgrimes	}
2741592Srgrimes
2751592Srgrimes	/*
2761592Srgrimes	 * Looking good so far.  Final test is to reset the
2771592Srgrimes	 * adapter.
2781592Srgrimes	 */
2791592Srgrimes	if ((error = ahareset(aha, /*hard_reset*/TRUE)) != 0) {
2801592Srgrimes		if (bootverbose)
2811592Srgrimes			printf("%s: Failed Reset\n", aha_name(aha));
2821592Srgrimes		return (ENXIO);
2831592Srgrimes	}
2841592Srgrimes
2851592Srgrimes	/*
2861592Srgrimes	 * Issue a buslogic command that will fail, and reject the board
28756668Sshin	 * if it doesn't.
28856668Sshin	 */
28956668Sshin	param = sizeof(esetup_info);
29056668Sshin	error = aha_cmd(aha, BOP_INQUIRE_ESETUP_INFO, &param, /*parmlen*/1,
2911592Srgrimes		       (u_int8_t*)&esetup_info, sizeof(esetup_info),
29236105Sache		       DEFAULT_CMD_TIMEOUT);
29336105Sache	if (error == 0)
29413139Speter		return ENXIO;
2951592Srgrimes
2961592Srgrimes	return (0);
2971592Srgrimes}
2981592Srgrimes
2991592Srgrimes/*
3001592Srgrimes * Pull the boards setup information and record it in our softc.
3011592Srgrimes */
30213139Speterint
3031592Srgrimesaha_fetch_adapter_info(struct aha_softc *aha)
3046740Sguido{
30582796Ssheldonh	board_id_data_t	board_id;
3061592Srgrimes	setup_data_t	setup_info;
30715196Sdg	config_data_t config_data;
30815196Sdg	u_int8_t length_param;
30915196Sdg	int	 error;
31015196Sdg
3111592Srgrimes	/* First record the firmware version */
31276096Smarkm	error = aha_cmd(aha, BOP_INQUIRE_BOARD_ID, NULL, /*parmlen*/0,
3131592Srgrimes		       (u_int8_t*)&board_id, sizeof(board_id),
3141592Srgrimes		       DEFAULT_CMD_TIMEOUT);
31570102Sphk	if (error != 0) {
31670102Sphk		printf("%s: aha_fetch_adapter_info - Failed Get Board Info\n",
31770102Sphk		       aha_name(aha));
31870102Sphk		return (error);
3191592Srgrimes	}
3201592Srgrimes	aha->firmware_ver[0] = board_id.firmware_rev_major;
3211592Srgrimes	aha->firmware_ver[1] = '.';
3221592Srgrimes	aha->firmware_ver[2] = board_id.firmware_rev_minor;
32370102Sphk	aha->firmware_ver[3] = '\0';
32470102Sphk
32570102Sphk	aha->boardid = board_id.board_type;
32670102Sphk
32717435Spst	switch (board_id.board_type) {
32817435Spst	case BOARD_1540_16HEAD_BIOS:
3299933Spst		strcpy(aha->model, "1540 16 head BIOS");
3309933Spst		break;
3316740Sguido	case BOARD_1540_64HEAD_BIOS:
33217435Spst		strcpy(aha->model, "1540 64 head BIOS");
3336740Sguido		break;
33417435Spst	case BOARD_1542:
3351592Srgrimes		strcpy(aha->model, "1540/1542 64 head BIOS");
3361592Srgrimes		break;
3371592Srgrimes	case BOARD_1640:
3381592Srgrimes		strcpy(aha->model, "1640");
3391592Srgrimes		break;
3401592Srgrimes	case BOARD_1740:
34117435Spst		strcpy(aha->model, "1740A/1742A/1744");
34217435Spst		break;
34317435Spst	case BOARD_1542C:
34417435Spst		strcpy(aha->model, "1542C");
34517435Spst		break;
34617435Spst	case BOARD_1542CF:
34717435Spst		strcpy(aha->model, "1542CF");
34817435Spst		break;
34917435Spst	case BOARD_1542CP:
35017435Spst		strcpy(aha->model, "1542CP");
35117483Sjulian		break;
35256668Sshin	default:
35317483Sjulian		strcpy(aha->model, "Unknown");
35417483Sjulian		break;
35517483Sjulian	}
35617483Sjulian	aha->max_sg = 16;
35717483Sjulian	aha->diff_bus = 0;
35817483Sjulian	aha->extended_lun = 0;
3591592Srgrimes	aha->extended_trans = 0;	/* XXX ???? XXX */
3601592Srgrimes	aha->max_ccbs = 16;		/* XXX ???? XXX */
3611592Srgrimes	/* Determine Sync/Wide/Disc settings */
3621592Srgrimes	length_param = sizeof(setup_info);
3631592Srgrimes	error = aha_cmd(aha, BOP_INQUIRE_SETUP_INFO, &length_param,
3641592Srgrimes		       /*paramlen*/1, (u_int8_t*)&setup_info,
3651592Srgrimes		       sizeof(setup_info), DEFAULT_CMD_TIMEOUT);
3661592Srgrimes	if (error != 0) {
3671592Srgrimes		printf("%s: aha_fetch_adapter_info - Failed "
3681592Srgrimes		       "Get Setup Info\n", aha_name(aha));
3691592Srgrimes		return (error);
37020042Storstenb	}
37120042Storstenb	if (setup_info.initiate_sync != 0) {
37220042Storstenb		aha->sync_permitted = ALL_TARGETS;
3731592Srgrimes	}
3741592Srgrimes	aha->disc_permitted = ALL_TARGETS;
37576096Smarkm
3761592Srgrimes	/* We need as many mailboxes as we can have ccbs */
3771592Srgrimes	aha->num_boxes = aha->max_ccbs;
37856668Sshin
37956668Sshin	/* Determine our SCSI ID */
38056668Sshin
38156668Sshin	error = aha_cmd(aha, BOP_INQUIRE_CONFIG, NULL, /*parmlen*/0,
38256668Sshin		       (u_int8_t*)&config_data, sizeof(config_data),
38356668Sshin		       DEFAULT_CMD_TIMEOUT);
38456668Sshin	if (error != 0) {
38556668Sshin		printf("%s: aha_fetch_adapter_info - Failed Get Config\n",
38656668Sshin		       aha_name(aha));
38756668Sshin		return (error);
38882796Ssheldonh	}
38982796Ssheldonh	aha->scsi_id = config_data.scsi_id;
39082796Ssheldonh	return (0);
39182796Ssheldonh}
39282460Snik
39382460Snik/*
39482460Snik * Start the board, ready for normal operation
39582460Snik */
3961592Srgrimesint
3971592Srgrimesaha_init(struct aha_softc* aha)
3981592Srgrimes{
3991592Srgrimes	/* Announce the Adapter */
4001592Srgrimes	printf("%s: AHA-%s FW Rev. %s (ID=%x)", aha_name(aha),
40115196Sdg	       aha->model, aha->firmware_ver, aha->boardid);
40225283Sdavidn
40325283Sdavidn	if (aha->diff_bus != 0)
40425283Sdavidn		printf("Diff ");
4051592Srgrimes
40615196Sdg	printf("SCSI Host Adapter, SCSI ID %d, %d CCBs\n", aha->scsi_id,
40715196Sdg	       aha->max_ccbs);
40815196Sdg
40915196Sdg	/*
41015196Sdg	 * Create our DMA tags.  These tags define the kinds of device
41115196Sdg	 * accessable memory allocations and memory mappings we will
41215196Sdg	 * need to perform during normal operation.
41315196Sdg	 *
41415196Sdg	 * Unless we need to further restrict the allocation, we rely
41556668Sshin	 * on the restrictions of the parent dmat, hence the common
41615196Sdg	 * use of MAXADDR and MAXSIZE.
41715196Sdg	 */
41815196Sdg
41915196Sdg	/* DMA tag for mapping buffers into device visible space. */
42015196Sdg	if (bus_dma_tag_create(aha->parent_dmat, /*alignment*/0, /*boundary*/0,
42115196Sdg			       /*lowaddr*/BUS_SPACE_MAXADDR,
42215196Sdg			       /*highaddr*/BUS_SPACE_MAXADDR,
42315196Sdg			       /*filter*/NULL, /*filterarg*/NULL,
42415196Sdg			       /*maxsize*/MAXBSIZE, /*nsegments*/AHA_NSEG,
42556668Sshin			       /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT,
42656668Sshin			       /*flags*/BUS_DMA_ALLOCNOW,
42756668Sshin			       &aha->buffer_dmat) != 0) {
42856668Sshin		goto error_exit;
42956668Sshin	}
43056668Sshin
43156668Sshin	aha->init_level++;
43256668Sshin	/* DMA tag for our mailboxes */
43356668Sshin	if (bus_dma_tag_create(aha->parent_dmat, /*alignment*/0, /*boundary*/0,
43456668Sshin			       /*lowaddr*/BUS_SPACE_MAXADDR,
43556668Sshin			       /*highaddr*/BUS_SPACE_MAXADDR,
43656668Sshin			       /*filter*/NULL, /*filterarg*/NULL,
43756668Sshin			       aha->num_boxes * (sizeof(aha_mbox_in_t)
43856668Sshin					       + sizeof(aha_mbox_out_t)),
43956668Sshin			       /*nsegments*/1,
44056668Sshin			       /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT,
44168901Skris			       /*flags*/0, &aha->mailbox_dmat) != 0) {
44256668Sshin		goto error_exit;
44368901Skris        }
44415196Sdg
44515196Sdg	aha->init_level++;
44656668Sshin
44756668Sshin	/* Allocation for our mailboxes */
44856668Sshin	if (bus_dmamem_alloc(aha->mailbox_dmat, (void **)&aha->out_boxes,
44964699Sru			     BUS_DMA_NOWAIT, &aha->mailbox_dmamap) != 0) {
45064699Sru		goto error_exit;
45115196Sdg	}
45215196Sdg
45315196Sdg	aha->init_level++;
45415196Sdg
45556668Sshin	/* And permanently map them */
45615196Sdg	bus_dmamap_load(aha->mailbox_dmat, aha->mailbox_dmamap,
45715196Sdg       			aha->out_boxes,
45815196Sdg			aha->num_boxes * (sizeof(aha_mbox_in_t)
45915196Sdg				       + sizeof(aha_mbox_out_t)),
46015196Sdg			ahamapmboxes, aha, /*flags*/0);
46115196Sdg
46256668Sshin	aha->init_level++;
46356668Sshin
46456668Sshin	aha->in_boxes = (aha_mbox_in_t *)&aha->out_boxes[aha->num_boxes];
46556668Sshin
46656668Sshin	ahainitmboxes(aha);
46756668Sshin
46856668Sshin	/* DMA tag for our ccb structures */
46956668Sshin	if (bus_dma_tag_create(aha->parent_dmat, /*alignment*/0, /*boundary*/0,
47056668Sshin			       /*lowaddr*/BUS_SPACE_MAXADDR,
47156668Sshin			       /*highaddr*/BUS_SPACE_MAXADDR,
47256668Sshin			       /*filter*/NULL, /*filterarg*/NULL,
47356668Sshin			       aha->max_ccbs * sizeof(struct aha_ccb),
47415196Sdg			       /*nsegments*/1,
47515196Sdg			       /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT,
47615196Sdg			       /*flags*/0, &aha->ccb_dmat) != 0) {
47715196Sdg		goto error_exit;
47815196Sdg        }
47915196Sdg
48015196Sdg	aha->init_level++;
48115196Sdg
48217483Sjulian	/* Allocation for our ccbs */
48317483Sjulian	if (bus_dmamem_alloc(aha->ccb_dmat, (void **)&aha->aha_ccb_array,
48417483Sjulian			     BUS_DMA_NOWAIT, &aha->ccb_dmamap) != 0) {
48517483Sjulian		goto error_exit;
48617483Sjulian	}
48717483Sjulian
48817483Sjulian	aha->init_level++;
48917483Sjulian
49017483Sjulian	/* And permanently map them */
49146078Simp	bus_dmamap_load(aha->ccb_dmat, aha->ccb_dmamap,
49217483Sjulian       			aha->aha_ccb_array,
49317483Sjulian			aha->max_ccbs * sizeof(struct aha_ccb),
49417483Sjulian			ahamapccbs, aha, /*flags*/0);
49517483Sjulian
49646078Simp	aha->init_level++;
49717483Sjulian
49817483Sjulian	/* DMA tag for our S/G structures.  We allocate in page sized chunks */
49917483Sjulian	if (bus_dma_tag_create(aha->parent_dmat, /*alignment*/0, /*boundary*/0,
50017483Sjulian			       /*lowaddr*/BUS_SPACE_MAXADDR,
50117483Sjulian			       /*highaddr*/BUS_SPACE_MAXADDR,
50217483Sjulian			       /*filter*/NULL, /*filterarg*/NULL,
50317483Sjulian			       PAGE_SIZE, /*nsegments*/1,
50415196Sdg			       /*maxsegsz*/BUS_SPACE_MAXSIZE_24BIT,
50515196Sdg			       /*flags*/0, &aha->sg_dmat) != 0) {
50615196Sdg		goto error_exit;
50715196Sdg        }
50856668Sshin
50915196Sdg	aha->init_level++;
51015196Sdg
51115196Sdg	/* Perform initial CCB allocation */
51215196Sdg	bzero(aha->aha_ccb_array, aha->max_ccbs * sizeof(struct aha_ccb));
51315196Sdg	ahaallocccbs(aha);
51415196Sdg
51515196Sdg	if (aha->num_ccbs == 0) {
51615196Sdg		printf("%s: aha_init - Unable to allocate initial ccbs\n",
51715196Sdg		       aha_name(aha));
51815196Sdg		goto error_exit;
51915196Sdg	}
52015196Sdg
52115196Sdg	/*
52215196Sdg	 * Note that we are going and return (to probe)
52315196Sdg	 */
52415196Sdg	return 0;
52515196Sdg
52615196Sdgerror_exit:
52715196Sdg
5281592Srgrimes	return (ENXIO);
52936612Sjb}
5301592Srgrimes
5311592Srgrimesint
53215196Sdgaha_attach(struct aha_softc *aha)
53315196Sdg{
53415196Sdg	int tagged_dev_openings;
53515196Sdg	struct cam_devq *devq;
53615196Sdg
53725283Sdavidn	/*
53825283Sdavidn	 * We reserve 1 ccb for error recovery, so don't
53956668Sshin	 * tell the XPT about it.
54025283Sdavidn	 */
54115196Sdg	tagged_dev_openings = 0;
54256668Sshin
54356668Sshin	/*
54415196Sdg	 * Create the device queue for our SIM.
54515196Sdg	 */
54615196Sdg	devq = cam_simq_alloc(aha->max_ccbs - 1);
54756668Sshin	if (devq == NULL)
54815196Sdg		return (ENOMEM);
54935482Sdg
55035482Sdg	/*
55135482Sdg	 * Construct our SIM entry
55235482Sdg	 */
55335482Sdg	aha->sim = cam_sim_alloc(ahaaction, ahapoll, "aha", aha, aha->unit,
55435482Sdg				2, tagged_dev_openings, devq);
55535482Sdg	if (aha->sim == NULL) {
55656668Sshin		cam_simq_free(devq);
55715196Sdg		return (ENOMEM);
55817435Spst	}
55931973Simp
56017435Spst	if (xpt_bus_register(aha->sim, 0) != CAM_SUCCESS) {
5611592Srgrimes		cam_sim_free(aha->sim, /*free_devq*/TRUE);
5621592Srgrimes		return (ENXIO);
5631592Srgrimes	}
5641592Srgrimes
5651592Srgrimes	if (xpt_create_path(&aha->path, /*periph*/NULL,
5661592Srgrimes			    cam_sim_path(aha->sim), CAM_TARGET_WILDCARD,
5671592Srgrimes			    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
5681592Srgrimes		xpt_bus_deregister(cam_sim_path(aha->sim));
5691592Srgrimes		cam_sim_free(aha->sim, /*free_devq*/TRUE);
5701592Srgrimes		return (ENXIO);
57156668Sshin	}
5721592Srgrimes
5731592Srgrimes	return (0);
5741592Srgrimes}
5751592Srgrimes
5761592Srgrimeschar *
5771592Srgrimesaha_name(struct aha_softc *aha)
5781592Srgrimes{
5791592Srgrimes	static char name[10];
5801592Srgrimes
5811592Srgrimes	sprintf(name, "aha%d", aha->unit);
5821592Srgrimes	return (name);
5831592Srgrimes}
5841592Srgrimes
5851592Srgrimesint
5861592Srgrimesaha_check_probed_iop(u_int ioport)
5871592Srgrimes{
5881592Srgrimes	u_int i;
5891592Srgrimes
5901592Srgrimes	for (i=0; i < AHA_NUM_ISAPORTS; i++) {
5911592Srgrimes		if (aha_isa_ports[i].addr == ioport) {
5921592Srgrimes			if (aha_isa_ports[i].probed != 0)
5931592Srgrimes				return (1);
59425283Sdavidn			else {
59525283Sdavidn				return (0);
59625283Sdavidn			}
5971592Srgrimes		}
59825283Sdavidn	}
5991592Srgrimes	return (1);
6001592Srgrimes}
6011592Srgrimes
6021592Srgrimesvoid
6031592Srgrimesaha_mark_probed_bio(isa_compat_io_t port)
6041592Srgrimes{
6051592Srgrimes	if (port < BIO_DISABLED)
6061592Srgrimes		aha_isa_ports[port].probed = 1;
6071592Srgrimes}
60825283Sdavidn
60927650Sdavidnvoid
61076096Smarkmaha_mark_probed_iop(u_int ioport)
61145422Sbrian{
61245422Sbrian	u_int i;
61325283Sdavidn
6141592Srgrimes	for (i = 0; i < AHA_NUM_ISAPORTS; i++) {
6151592Srgrimes		if (ioport == aha_isa_ports[i].addr) {
6161592Srgrimes			aha_isa_ports[i].probed = 1;
6171592Srgrimes			break;
6181592Srgrimes		}
6191592Srgrimes	}
6201592Srgrimes}
6211592Srgrimes
6221592Srgrimesstatic void
6231592Srgrimesahaallocccbs(struct aha_softc *aha)
6241592Srgrimes{
6251592Srgrimes	struct aha_ccb *next_ccb;
62676096Smarkm	struct sg_map_node *sg_map;
6271592Srgrimes	bus_addr_t physaddr;
62831329Scharnier	aha_sg_t *segs;
6291592Srgrimes	int newcount;
6301592Srgrimes	int i;
63125283Sdavidn
6321592Srgrimes	next_ccb = &aha->aha_ccb_array[aha->num_ccbs];
63325283Sdavidn
63425283Sdavidn	sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT);
63525283Sdavidn
63625283Sdavidn	if (sg_map == NULL)
63725283Sdavidn		return;
63825283Sdavidn
63925283Sdavidn	/* Allocate S/G space for the next batch of CCBS */
64025283Sdavidn	if (bus_dmamem_alloc(aha->sg_dmat, (void **)&sg_map->sg_vaddr,
64125283Sdavidn			     BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) {
64225283Sdavidn		free(sg_map, M_DEVBUF);
64356668Sshin		return;
64425283Sdavidn	}
64525283Sdavidn
64625283Sdavidn	SLIST_INSERT_HEAD(&aha->sg_maps, sg_map, links);
64725283Sdavidn
64825283Sdavidn	bus_dmamap_load(aha->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr,
64925283Sdavidn			PAGE_SIZE, ahamapsgs, aha, /*flags*/0);
65025283Sdavidn
65125283Sdavidn	segs = sg_map->sg_vaddr;
65276096Smarkm	physaddr = sg_map->sg_physaddr;
65357124Sshin
65456668Sshin	newcount = (PAGE_SIZE / (AHA_NSEG * sizeof(aha_sg_t)));
65556668Sshin	for (i = 0; aha->num_ccbs < aha->max_ccbs && i < newcount; i++) {
65656668Sshin		int error;
65756668Sshin
65856668Sshin		next_ccb->sg_list = segs;
65956668Sshin		next_ccb->sg_list_phys = physaddr;
66057124Sshin		next_ccb->flags = BCCB_FREE;
66125283Sdavidn		error = bus_dmamap_create(aha->buffer_dmat, /*flags*/0,
66225283Sdavidn					  &next_ccb->dmamap);
66325283Sdavidn		if (error != 0)
66425283Sdavidn			break;
66525283Sdavidn		SLIST_INSERT_HEAD(&aha->free_aha_ccbs, next_ccb, links);
66625283Sdavidn		segs += AHA_NSEG;
66725283Sdavidn		physaddr += (AHA_NSEG * sizeof(aha_sg_t));
66862100Sdavidn		next_ccb++;
66956668Sshin		aha->num_ccbs++;
67056668Sshin	}
67156668Sshin
67225283Sdavidn	/* Reserve a CCB for error recovery */
67356668Sshin	if (aha->recovery_bccb == NULL) {
67425283Sdavidn		aha->recovery_bccb = SLIST_FIRST(&aha->free_aha_ccbs);
67525283Sdavidn		SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links);
67625283Sdavidn	}
67725283Sdavidn}
67825283Sdavidn
67925283Sdavidnstatic __inline void
68025283Sdavidnahafreeccb(struct aha_softc *aha, struct aha_ccb *bccb)
68125283Sdavidn{
68225283Sdavidn	int s;
68325283Sdavidn
68425283Sdavidn	s = splcam();
68525283Sdavidn	if ((bccb->flags & BCCB_ACTIVE) != 0)
68625283Sdavidn		LIST_REMOVE(&bccb->ccb->ccb_h, sim_links.le);
68756668Sshin	if (aha->resource_shortage != 0
68856668Sshin	 && (bccb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) {
68956668Sshin		bccb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
69056668Sshin		aha->resource_shortage = FALSE;
69156668Sshin	}
69256668Sshin	bccb->flags = BCCB_FREE;
69325283Sdavidn	SLIST_INSERT_HEAD(&aha->free_aha_ccbs, bccb, links);
69456668Sshin	splx(s);
69562100Sdavidn}
69656668Sshin
69762100Sdavidnstatic struct aha_ccb*
69825283Sdavidnahagetccb(struct aha_softc *aha)
69957124Sshin{
70057124Sshin	struct	aha_ccb* bccb;
70157124Sshin	int	s;
70257124Sshin
70357124Sshin	s = splcam();
70457124Sshin	if ((bccb = SLIST_FIRST(&aha->free_aha_ccbs)) != NULL) {
70557124Sshin		SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links);
70662100Sdavidn	} else if (aha->num_ccbs < aha->max_ccbs) {
70762100Sdavidn		ahaallocccbs(aha);
70857124Sshin		bccb = SLIST_FIRST(&aha->free_aha_ccbs);
70962100Sdavidn		if (bccb == NULL)
71062100Sdavidn			printf("%s: Can't malloc BCCB\n", aha_name(aha));
71162100Sdavidn		else
71225283Sdavidn			SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links);
71325283Sdavidn	}
71425283Sdavidn	splx(s);
71525283Sdavidn
71625283Sdavidn	return (bccb);
71725283Sdavidn}
71825283Sdavidn
71925283Sdavidnstatic void
72025283Sdavidnahaaction(struct cam_sim *sim, union ccb *ccb)
72125283Sdavidn{
72225283Sdavidn	struct	aha_softc *aha;
72325283Sdavidn	int	s;
72425283Sdavidn
72557124Sshin	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahaaction\n"));
72657124Sshin
72725283Sdavidn	aha = (struct aha_softc *)cam_sim_softc(sim);
72825283Sdavidn
72956668Sshin	switch (ccb->ccb_h.func_code) {
73025283Sdavidn	/* Common cases first */
73125283Sdavidn	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
73256668Sshin	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
73357124Sshin	{
73456668Sshin		struct	aha_ccb	*bccb;
73557124Sshin		struct	aha_hccb *hccb;
73656668Sshin
73756668Sshin		/*
73856668Sshin		 * get a bccb to use.
73957124Sshin		 */
74056668Sshin		if ((bccb = ahagetccb(aha)) == NULL) {
74156668Sshin			int s;
74256668Sshin
74356668Sshin			s = splcam();
74457124Sshin			aha->resource_shortage = TRUE;
74557124Sshin			splx(s);
74656668Sshin			xpt_freeze_simq(aha->sim, /*count*/1);
74756668Sshin			ccb->ccb_h.status = CAM_REQUEUE_REQ;
74856668Sshin			xpt_done(ccb);
74956668Sshin			return;
75056668Sshin		}
75157124Sshin
75256668Sshin		hccb = &bccb->hccb;
75325283Sdavidn
75425283Sdavidn		/*
75525283Sdavidn		 * So we can find the BCCB when an abort is requested
75625283Sdavidn		 */
75725283Sdavidn		bccb->ccb = ccb;
75825283Sdavidn		ccb->ccb_h.ccb_bccb_ptr = bccb;
75925283Sdavidn		ccb->ccb_h.ccb_aha_ptr = aha;
76025283Sdavidn
76125283Sdavidn		/*
76225283Sdavidn		 * Put all the arguments for the xfer in the bccb
76325283Sdavidn		 */
76425283Sdavidn		hccb->target = ccb->ccb_h.target_id;
76525283Sdavidn		hccb->lun = ccb->ccb_h.target_lun;
76625283Sdavidn		hccb->ahastat = 0;
76756668Sshin		hccb->sdstat = 0;
76825283Sdavidn
76925283Sdavidn		if (ccb->ccb_h.func_code == XPT_SCSI_IO) {
77025283Sdavidn			struct ccb_scsiio *csio;
77125283Sdavidn			struct ccb_hdr *ccbh;
77225283Sdavidn
77325283Sdavidn			csio = &ccb->csio;
77425283Sdavidn			ccbh = &csio->ccb_h;
77525283Sdavidn			hccb->opcode = INITIATOR_CCB_WRESID;
77625283Sdavidn			hccb->datain = (ccb->ccb_h.flags & CAM_DIR_IN) != 0;
77725283Sdavidn			hccb->dataout = (ccb->ccb_h.flags & CAM_DIR_OUT) != 0;
77825283Sdavidn			hccb->cmd_len = csio->cdb_len;
77925283Sdavidn			if (hccb->cmd_len > sizeof(hccb->scsi_cdb)) {
78025283Sdavidn				ccb->ccb_h.status = CAM_REQ_INVALID;
78125283Sdavidn				ahafreeccb(aha, bccb);
78225283Sdavidn				xpt_done(ccb);
78325283Sdavidn				return;
78425283Sdavidn			}
78525283Sdavidn			hccb->sense_len = csio->sense_len;
78625283Sdavidn			if ((ccbh->flags & CAM_CDB_POINTER) != 0) {
78725283Sdavidn				if ((ccbh->flags & CAM_CDB_PHYS) == 0) {
78825283Sdavidn					bcopy(csio->cdb_io.cdb_ptr,
78956668Sshin					      hccb->scsi_cdb, hccb->cmd_len);
79056668Sshin				} else {
79156668Sshin					/* I guess I could map it in... */
79225283Sdavidn					ccbh->status = CAM_REQ_INVALID;
79325283Sdavidn					ahafreeccb(aha, bccb);
79425283Sdavidn					xpt_done(ccb);
79525283Sdavidn					return;
79625283Sdavidn				}
79725283Sdavidn			} else {
79856668Sshin				bcopy(csio->cdb_io.cdb_bytes,
79956668Sshin				      hccb->scsi_cdb, hccb->cmd_len);
80025283Sdavidn			}
80125283Sdavidn			/*
80256668Sshin			 * If we have any data to send with this command,
80356668Sshin			 * map it into bus space.
80456668Sshin			 */
80556668Sshin		        /* Only use S/G if there is a transfer */
80657124Sshin			if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
80725283Sdavidn				if ((ccbh->flags & CAM_SCATTER_VALID) == 0) {
80856668Sshin					/*
80956668Sshin					 * We've been given a pointer
81056668Sshin					 * to a single buffer.
81156668Sshin					 */
81256668Sshin					if ((ccbh->flags & CAM_DATA_PHYS)==0) {
81356668Sshin						int s;
81456668Sshin						int error;
81556668Sshin
81656668Sshin						s = splsoftvm();
81756668Sshin						error = bus_dmamap_load(
81825283Sdavidn						    aha->buffer_dmat,
81956668Sshin						    bccb->dmamap,
82056668Sshin						    csio->data_ptr,
82125283Sdavidn						    csio->dxfer_len,
82262100Sdavidn						    ahaexecuteccb,
82357124Sshin						    bccb,
82425283Sdavidn						    /*flags*/0);
82525283Sdavidn						if (error == EINPROGRESS) {
82625283Sdavidn							/*
82756668Sshin							 * So as to maintain
82856668Sshin							 * ordering, freeze the
82957124Sshin							 * controller queue
83056668Sshin							 * until our mapping is
83157124Sshin							 * returned.
83256668Sshin							 */
83356668Sshin							xpt_freeze_simq(aha->sim,
83456668Sshin									1);
83556668Sshin							csio->ccb_h.status |=
83656668Sshin							    CAM_RELEASE_SIMQ;
83762100Sdavidn						}
83862100Sdavidn						splx(s);
83925283Sdavidn					} else {
84056668Sshin						struct bus_dma_segment seg;
84125283Sdavidn
84225283Sdavidn						/* Pointer to physical buffer */
84325283Sdavidn						seg.ds_addr =
84425283Sdavidn						    (bus_addr_t)csio->data_ptr;
84525283Sdavidn						seg.ds_len = csio->dxfer_len;
84625283Sdavidn						ahaexecuteccb(bccb, &seg, 1, 0);
84725283Sdavidn					}
8481592Srgrimes				} else {
8491592Srgrimes					struct bus_dma_segment *segs;
8501592Srgrimes
8511592Srgrimes					if ((ccbh->flags & CAM_DATA_PHYS) != 0)
8521592Srgrimes						panic("ahaaction - Physical "
8531592Srgrimes						      "segment pointers "
8541592Srgrimes						      "unsupported");
8551592Srgrimes
8561592Srgrimes					if ((ccbh->flags&CAM_SG_LIST_PHYS)==0)
8571592Srgrimes						panic("ahaaction - Virtual "
8581592Srgrimes						      "segment addresses "
8591592Srgrimes						      "unsupported");
8601592Srgrimes
8611592Srgrimes					/* Just use the segments provided */
8621592Srgrimes					segs = (struct bus_dma_segment *)
8631592Srgrimes					    csio->data_ptr;
8641592Srgrimes					ahaexecuteccb(bccb, segs,
8651592Srgrimes						     csio->sglist_cnt, 0);
8661592Srgrimes				}
8671592Srgrimes			} else {
8681592Srgrimes				ahaexecuteccb(bccb, NULL, 0, 0);
8691592Srgrimes			}
8701592Srgrimes		} else {
8711592Srgrimes			hccb->opcode = INITIATOR_BUS_DEV_RESET;
8721592Srgrimes			/* No data transfer */
8731592Srgrimes			hccb->datain = TRUE;
8741592Srgrimes			hccb->dataout = TRUE;
8751592Srgrimes			hccb->cmd_len = 0;
8761592Srgrimes			hccb->sense_len = 0;
8771592Srgrimes			ahaexecuteccb(bccb, NULL, 0, 0);
8781592Srgrimes		}
8791592Srgrimes		break;
8801592Srgrimes	}
8811592Srgrimes	case XPT_EN_LUN:		/* Enable LUN as a target */
8821592Srgrimes	case XPT_TARGET_IO:		/* Execute target I/O request */
8831592Srgrimes	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
8841592Srgrimes	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/
8851592Srgrimes	case XPT_ABORT:			/* Abort the specified CCB */
8861592Srgrimes		/* XXX Implement */
8871592Srgrimes		ccb->ccb_h.status = CAM_REQ_INVALID;
8881592Srgrimes		xpt_done(ccb);
8891592Srgrimes		break;
8901592Srgrimes	case XPT_SET_TRAN_SETTINGS:
8911592Srgrimes	{
8921592Srgrimes		/* XXX Implement */
8931592Srgrimes		ccb->ccb_h.status = CAM_REQ_CMP;
8941592Srgrimes		xpt_done(ccb);
8951592Srgrimes		break;
8961592Srgrimes	}
89764778Ssheldonh	case XPT_GET_TRAN_SETTINGS:
8981592Srgrimes	/* Get default/user set transfer settings for the target */
8991592Srgrimes	{
9001592Srgrimes		struct	ccb_trans_settings *cts;
9011592Srgrimes		u_int	target_mask;
9021592Srgrimes
9031592Srgrimes		cts = &ccb->cts;
9041592Srgrimes		target_mask = 0x01 << ccb->ccb_h.target_id;
9051592Srgrimes		if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) {
9061592Srgrimes			cts->flags = 0;
9071592Srgrimes			if ((aha->disc_permitted & target_mask) != 0)
9081592Srgrimes				cts->flags |= CCB_TRANS_DISC_ENB;
9091592Srgrimes			cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
9101592Srgrimes			if ((aha->sync_permitted & target_mask) != 0)
9111592Srgrimes				cts->sync_period = 50;
9121592Srgrimes			else
9131592Srgrimes				cts->sync_period = 0;
9141592Srgrimes
9151592Srgrimes			if (cts->sync_period != 0)
9161592Srgrimes				cts->sync_offset = 15;
9171592Srgrimes
9181592Srgrimes			cts->valid = CCB_TRANS_SYNC_RATE_VALID
9191592Srgrimes				   | CCB_TRANS_SYNC_OFFSET_VALID
92017435Spst				   | CCB_TRANS_BUS_WIDTH_VALID
92117435Spst				   | CCB_TRANS_DISC_VALID
92217435Spst				   | CCB_TRANS_TQ_VALID;
9231592Srgrimes		} else {
9241592Srgrimes			ahafetchtransinfo(aha, cts);
9251592Srgrimes		}
9261592Srgrimes
9271592Srgrimes		ccb->ccb_h.status = CAM_REQ_CMP;
9281592Srgrimes		xpt_done(ccb);
92936349Ssteve		break;
93036349Ssteve	}
9311592Srgrimes	case XPT_CALC_GEOMETRY:
93225283Sdavidn	{
93325283Sdavidn		struct	  ccb_calc_geometry *ccg;
93425283Sdavidn		u_int32_t size_mb;
9351592Srgrimes		u_int32_t secs_per_cylinder;
93625283Sdavidn
9371592Srgrimes		ccg = &ccb->ccg;
9381592Srgrimes		size_mb = ccg->volume_size
9391592Srgrimes			/ ((1024L * 1024L) / ccg->block_size);
9403938Spst
9411592Srgrimes		if (size_mb >= 1024 && (aha->extended_trans != 0)) {
9421592Srgrimes			if (size_mb >= 2048) {
9431592Srgrimes				ccg->heads = 255;
9441592Srgrimes				ccg->secs_per_track = 63;
9451592Srgrimes			} else {
9461592Srgrimes				ccg->heads = 128;
9471592Srgrimes				ccg->secs_per_track = 32;
94820042Storstenb			}
94920042Storstenb		} else {
95020042Storstenb			ccg->heads = 64;
95120042Storstenb			ccg->secs_per_track = 32;
95220042Storstenb		}
95317478Smarkm		secs_per_cylinder = ccg->heads * ccg->secs_per_track;
9541592Srgrimes		ccg->cylinders = ccg->volume_size / secs_per_cylinder;
9551592Srgrimes		ccb->ccb_h.status = CAM_REQ_CMP;
9561592Srgrimes		xpt_done(ccb);
9571592Srgrimes		break;
9581592Srgrimes	}
9591592Srgrimes	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
9601592Srgrimes	{
96136349Ssteve		ahareset(aha, /*hardreset*/TRUE);
9621592Srgrimes		ccb->ccb_h.status = CAM_REQ_CMP;
9631592Srgrimes		xpt_done(ccb);
9641592Srgrimes		break;
9651592Srgrimes	}
9661592Srgrimes	case XPT_TERM_IO:		/* Terminate the I/O process */
9671592Srgrimes		/* XXX Implement */
9681592Srgrimes		ccb->ccb_h.status = CAM_REQ_INVALID;
9691592Srgrimes		xpt_done(ccb);
9701592Srgrimes		break;
9711592Srgrimes	case XPT_PATH_INQ:		/* Path routing inquiry */
9721592Srgrimes	{
97379469Smarkm		struct ccb_pathinq *cpi = &ccb->cpi;
97479469Smarkm
97584146Sache		cpi->version_num = 1; /* XXX??? */
97684146Sache		cpi->hba_inquiry = PI_SDTR_ABLE;
97784146Sache		cpi->target_sprt = 0;
97884146Sache		cpi->hba_misc = 0;
97984146Sache		cpi->hba_eng_cnt = 0;
9802193Sguido		cpi->max_target = aha->wide_bus ? 15 : 7;
9811592Srgrimes		cpi->max_lun = 7;
9822193Sguido		cpi->initiator_id = aha->scsi_id;
9831592Srgrimes		cpi->bus_id = cam_sim_bus(sim);
9841592Srgrimes		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
9851592Srgrimes		strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN);
9861592Srgrimes		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
9871592Srgrimes		cpi->unit_number = cam_sim_unit(sim);
9881592Srgrimes		cpi->ccb_h.status = CAM_REQ_CMP;
9891592Srgrimes		xpt_done(ccb);
9901592Srgrimes		break;
9911592Srgrimes	}
9921592Srgrimes	default:
99317435Spst		ccb->ccb_h.status = CAM_REQ_INVALID;
9941592Srgrimes		xpt_done(ccb);
9951592Srgrimes		break;
99636349Ssteve	}
99717435Spst}
9981592Srgrimes
99936349Sstevestatic void
10001592Srgrimesahaexecuteccb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
10011592Srgrimes{
10021592Srgrimes	struct	 aha_ccb *bccb;
10031592Srgrimes	union	 ccb *ccb;
10041592Srgrimes	struct	 aha_softc *aha;
100517435Spst	int	 s, i;
100625187Sdavidn	u_int32_t paddr;
10071592Srgrimes
10081592Srgrimes	bccb = (struct aha_ccb *)arg;
10091592Srgrimes	ccb = bccb->ccb;
10101592Srgrimes	aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr;
101125187Sdavidn
101225187Sdavidn	if (error != 0) {
101325187Sdavidn		if (error != EFBIG)
101425187Sdavidn			printf("%s: Unexepected error 0x%x returned from "
101525187Sdavidn			       "bus_dmamap_load\n", aha_name(aha), error);
101625187Sdavidn		if (ccb->ccb_h.status == CAM_REQ_INPROG) {
101725187Sdavidn			xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
101825187Sdavidn			ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN;
101925187Sdavidn		}
102036349Ssteve		ahafreeccb(aha, bccb);
102136349Ssteve		xpt_done(ccb);
102236349Ssteve		return;
102336349Ssteve	}
102436349Ssteve
102536349Ssteve	if (nseg != 0) {
102636349Ssteve		aha_sg_t *sg;
102736349Ssteve		bus_dma_segment_t *end_seg;
102825187Sdavidn		bus_dmasync_op_t op;
102925187Sdavidn
103025187Sdavidn		end_seg = dm_segs + nseg;
103125187Sdavidn
10321592Srgrimes		/* Copy the segments into our SG list */
103325187Sdavidn		sg = bccb->sg_list;
103425187Sdavidn		while (dm_segs < end_seg) {
103525187Sdavidn			ahautoa24(dm_segs->ds_len, sg->len);
103625187Sdavidn			ahautoa24(dm_segs->ds_addr, sg->addr);
103725187Sdavidn			sg++;
10381592Srgrimes			dm_segs++;
10391592Srgrimes		}
10401592Srgrimes
10411592Srgrimes		if (nseg > 1) {
10421592Srgrimes			bccb->hccb.opcode = INITIATOR_SG_CCB_WRESID;
10431592Srgrimes			ahautoa24((sizeof(aha_sg_t) * nseg),
10441592Srgrimes				  bccb->hccb.data_len);
10451592Srgrimes			ahautoa24(bccb->sg_list_phys, bccb->hccb.data_addr);
10461592Srgrimes		} else {
10471592Srgrimes			bcopy(bccb->sg_list->len, bccb->hccb.data_len, 3);
10481592Srgrimes			bcopy(bccb->sg_list->addr, bccb->hccb.data_addr, 3);
10491592Srgrimes		}
10501592Srgrimes
105174874Smarkm		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
105274874Smarkm			op = BUS_DMASYNC_PREREAD;
105374874Smarkm		else
10541592Srgrimes			op = BUS_DMASYNC_PREWRITE;
10551592Srgrimes
10561592Srgrimes		bus_dmamap_sync(aha->buffer_dmat, bccb->dmamap, op);
105729140Stg
10581592Srgrimes	} else {
105925101Sdavidn		bccb->hccb.opcode = INITIATOR_CCB_WRESID;
106025101Sdavidn		ahautoa24(0, bccb->hccb.data_len);
106125101Sdavidn		ahautoa24(0, bccb->hccb.data_addr);
106225101Sdavidn	}
106374874Smarkm
106474874Smarkm	s = splcam();
106574874Smarkm
106674874Smarkm	/*
106774874Smarkm	 * Last time we need to check if this CCB needs to
106874874Smarkm	 * be aborted.
106974874Smarkm	 */
107074874Smarkm	if (ccb->ccb_h.status != CAM_REQ_INPROG) {
107174874Smarkm		if (nseg != 0)
10721592Srgrimes			bus_dmamap_unload(aha->buffer_dmat, bccb->dmamap);
10731592Srgrimes		ahafreeccb(aha, bccb);
107417435Spst		xpt_done(ccb);
10751592Srgrimes		splx(s);
10761592Srgrimes		return;
107774874Smarkm	}
107851433Smarkm
107951433Smarkm	bccb->flags = BCCB_ACTIVE;
108051433Smarkm	ccb->ccb_h.status |= CAM_SIM_QUEUED;
108151433Smarkm	LIST_INSERT_HEAD(&aha->pending_ccbs, &ccb->ccb_h, sim_links.le);
108251433Smarkm
108351433Smarkm	ccb->ccb_h.timeout_ch =
108451433Smarkm	    timeout(ahatimeout, (caddr_t)bccb,
108551433Smarkm		    (ccb->ccb_h.timeout * hz) / 1000);
108651433Smarkm
108751433Smarkm	/* Tell the adapter about this command */
108851433Smarkm	paddr = ahaccbvtop(aha, bccb);
108951433Smarkm	ahautoa24(paddr, aha->cur_outbox->ccb_addr);
109051433Smarkm	if (aha->cur_outbox->action_code != BMBO_FREE)
109151433Smarkm		panic("%s: Too few mailboxes or to many ccbs???", aha_name(aha));
109251433Smarkm	aha->cur_outbox->action_code = BMBO_START;
109351433Smarkm	aha_outb(aha, COMMAND_REG, BOP_START_MBOX);
109451433Smarkm
109551433Smarkm	ahanextoutbox(aha);
109651433Smarkm	splx(s);
109751433Smarkm}
109851433Smarkm
109951433Smarkmvoid
110051433Smarkmaha_intr(void *arg)
110151433Smarkm{
110251433Smarkm	struct	aha_softc *aha;
110351433Smarkm	u_int	intstat;
110451433Smarkm
110551433Smarkm	aha = (struct aha_softc *)arg;
110651433Smarkm	while (((intstat = aha_inb(aha, INTSTAT_REG)) & INTR_PENDING) != 0) {
110751433Smarkm		if ((intstat & CMD_COMPLETE) != 0) {
110851433Smarkm			aha->latched_status = aha_inb(aha, STATUS_REG);
110951433Smarkm			aha->command_cmp = TRUE;
111051433Smarkm		}
111151433Smarkm
111251433Smarkm		aha_outb(aha, CONTROL_REG, RESET_INTR);
111351433Smarkm
111451433Smarkm		if ((intstat & IMB_LOADED) != 0) {
111551433Smarkm			while (aha->cur_inbox->comp_code != BMBI_FREE) {
111651433Smarkm				u_int32_t	paddr;
111751433Smarkm				paddr = aha_a24tou(aha->cur_inbox->ccb_addr);
111851433Smarkm				ahadone(aha,
111951433Smarkm				       ahaccbptov(aha, paddr),
112051433Smarkm				       aha->cur_inbox->comp_code);
112151433Smarkm				aha->cur_inbox->comp_code = BMBI_FREE;
112251433Smarkm				ahanextinbox(aha);
112351433Smarkm			}
112451433Smarkm		}
112551433Smarkm
112651433Smarkm		if ((intstat & SCSI_BUS_RESET) != 0) {
112751433Smarkm			ahareset(aha, /*hardreset*/FALSE);
112851433Smarkm		}
112951433Smarkm	}
113051433Smarkm}
113151433Smarkm
113251433Smarkmstatic void
113351433Smarkmahadone(struct aha_softc *aha, struct aha_ccb *bccb, aha_mbi_comp_code_t comp_code)
113451433Smarkm{
113551433Smarkm	union  ccb	  *ccb;
113651433Smarkm	struct ccb_scsiio *csio;
113751433Smarkm
113851433Smarkm	ccb = bccb->ccb;
113951433Smarkm	csio = &bccb->ccb->csio;
114051433Smarkm
114151433Smarkm	if ((bccb->flags & BCCB_ACTIVE) == 0) {
114251433Smarkm		printf("%s: ahadone - Attempt to free non-active BCCB 0x%x\n",
114351433Smarkm		       aha_name(aha), (intptr_t)bccb);
114451433Smarkm		return;
114551433Smarkm	}
114651433Smarkm
114751433Smarkm	if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
114851433Smarkm		bus_dmasync_op_t op;
114951433Smarkm
115051433Smarkm		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
115167007Sguido			op = BUS_DMASYNC_POSTREAD;
115267007Sguido		else
115367007Sguido			op = BUS_DMASYNC_POSTWRITE;
115467007Sguido		bus_dmamap_sync(aha->buffer_dmat, bccb->dmamap, op);
115567007Sguido		bus_dmamap_unload(aha->buffer_dmat, bccb->dmamap);
115667007Sguido	}
115767007Sguido
115851433Smarkm	if (bccb == aha->recovery_bccb) {
115951433Smarkm		/*
116051433Smarkm		 * The recovery BCCB does not have a CCB associated
116151433Smarkm		 * with it, so short circuit the normal error handling.
116251433Smarkm		 * We now traverse our list of pending CCBs and process
116351433Smarkm		 * any that were terminated by the recovery CCBs action.
116451433Smarkm		 * We also reinstate timeouts for all remaining, pending,
116551433Smarkm		 * CCBs.
116651433Smarkm		 */
116751433Smarkm		struct cam_path *path;
116851433Smarkm		struct ccb_hdr *ccb_h;
116951433Smarkm		cam_status error;
117051433Smarkm
117151433Smarkm		/* Notify all clients that a BDR occured */
117251433Smarkm		error = xpt_create_path(&path, /*periph*/NULL,
117351433Smarkm					cam_sim_path(aha->sim),
117451433Smarkm					bccb->hccb.target,
117551433Smarkm					CAM_LUN_WILDCARD);
117651433Smarkm
117751433Smarkm		if (error == CAM_REQ_CMP)
117851433Smarkm			xpt_async(AC_SENT_BDR, path, NULL);
117951433Smarkm
118051433Smarkm		ccb_h = LIST_FIRST(&aha->pending_ccbs);
118151433Smarkm		while (ccb_h != NULL) {
118251433Smarkm			struct aha_ccb *pending_bccb;
118351433Smarkm
118451433Smarkm			pending_bccb = (struct aha_ccb *)ccb_h->ccb_bccb_ptr;
118551433Smarkm			if (pending_bccb->hccb.target == bccb->hccb.target) {
118651433Smarkm				pending_bccb->hccb.ahastat = AHASTAT_HA_BDR;
118751433Smarkm				ccb_h = LIST_NEXT(ccb_h, sim_links.le);
118851433Smarkm				ahadone(aha, pending_bccb, BMBI_ERROR);
118951433Smarkm			} else {
119051433Smarkm				ccb_h->timeout_ch =
119151433Smarkm				    timeout(ahatimeout, (caddr_t)pending_bccb,
119251433Smarkm					    (ccb_h->timeout * hz) / 1000);
119351433Smarkm				ccb_h = LIST_NEXT(ccb_h, sim_links.le);
119451433Smarkm			}
119551433Smarkm		}
119674874Smarkm		printf("%s: No longer in timeout\n", aha_name(aha));
119751433Smarkm		return;
119851433Smarkm	}
119951433Smarkm
120051433Smarkm	untimeout(ahatimeout, bccb, ccb->ccb_h.timeout_ch);
120174874Smarkm
120274874Smarkm	switch (comp_code) {
120374874Smarkm	case BMBI_FREE:
120474874Smarkm		printf("%s: ahadone - CCB completed with free status!\n",
120574874Smarkm		       aha_name(aha));
120674874Smarkm		break;
120774874Smarkm	case BMBI_NOT_FOUND:
120874874Smarkm		printf("%s: ahadone - CCB Abort failed to find CCB\n",
120974874Smarkm		       aha_name(aha));
121074874Smarkm		break;
121174874Smarkm	case BMBI_ABORT:
121251433Smarkm	case BMBI_ERROR:
121374874Smarkm		/* An error occured */
121474874Smarkm		switch(bccb->hccb.ahastat) {
121574874Smarkm		case AHASTAT_DATARUN_ERROR:
121674874Smarkm			if (bccb->hccb.data_len <= 0) {
121774874Smarkm				csio->ccb_h.status = CAM_DATA_RUN_ERR;
121874874Smarkm				break;
121974874Smarkm			}
122051433Smarkm			/* FALLTHROUGH */
122151433Smarkm		case AHASTAT_NOERROR:
122251433Smarkm			csio->scsi_status = bccb->hccb.sdstat;
122374874Smarkm			csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
122451433Smarkm			switch(csio->scsi_status) {
12251592Srgrimes			case SCSI_STATUS_CHECK_COND:
12261592Srgrimes			case SCSI_STATUS_CMD_TERMINATED:
12271592Srgrimes				csio->ccb_h.status |= CAM_AUTOSNS_VALID;
12281592Srgrimes				/*
122917435Spst				 * The aha writes the sense data at different
12301592Srgrimes				 * offsets based on the scsi cmd len
123125101Sdavidn				 */
123225101Sdavidn				bcopy((caddr_t) &bccb->hccb.scsi_cdb +
123325101Sdavidn					bccb->hccb.cmd_len,
123474874Smarkm					(caddr_t) &csio->sense_data,
123574874Smarkm					bccb->hccb.sense_len);
123674874Smarkm				break;
12371592Srgrimes			default:
12381592Srgrimes				break;
12391592Srgrimes			case SCSI_STATUS_OK:
12401592Srgrimes				csio->ccb_h.status = CAM_REQ_CMP;
12411592Srgrimes				break;
12421592Srgrimes			}
12431592Srgrimes			csio->resid = aha_a24tou(bccb->hccb.data_len);
124417435Spst			break;
124517435Spst		case AHASTAT_SELTIMEOUT:
124617435Spst			csio->ccb_h.status = CAM_SEL_TIMEOUT;
124717435Spst			break;
124874874Smarkm		case AHASTAT_UNEXPECTED_BUSFREE:
124951433Smarkm			csio->ccb_h.status = CAM_UNEXP_BUSFREE;
125051433Smarkm			break;
125117435Spst		case AHASTAT_INVALID_PHASE:
125217435Spst			csio->ccb_h.status = CAM_SEQUENCE_FAIL;
125364103Ssheldonh			break;
12541592Srgrimes		case AHASTAT_INVALID_ACTION_CODE:
125517435Spst			panic("%s: Inavlid Action code", aha_name(aha));
125617435Spst			break;
125717435Spst		case AHASTAT_INVALID_OPCODE:
125817435Spst			panic("%s: Inavlid CCB Opcode code %x hccb = %p",
125917435Spst			      aha_name(aha), bccb->hccb.opcode, &bccb->hccb);
126017435Spst			break;
126151433Smarkm		case AHASTAT_LINKED_CCB_LUN_MISMATCH:
126217435Spst			/* We don't even support linked commands... */
126317435Spst			panic("%s: Linked CCB Lun Mismatch", aha_name(aha));
126417435Spst			break;
12651592Srgrimes		case AHASTAT_INVALID_CCB_OR_SG_PARAM:
12661592Srgrimes			panic("%s: Invalid CCB or SG list", aha_name(aha));
12671592Srgrimes			break;
12681592Srgrimes		case AHASTAT_HA_SCSI_BUS_RESET:
12691592Srgrimes			if ((csio->ccb_h.status & CAM_STATUS_MASK)
12701592Srgrimes			 != CAM_CMD_TIMEOUT)
12711592Srgrimes				csio->ccb_h.status = CAM_SCSI_BUS_RESET;
12721592Srgrimes			break;
12731592Srgrimes		case AHASTAT_HA_BDR:
12741592Srgrimes			if ((bccb->flags & BCCB_DEVICE_RESET) == 0)
12751592Srgrimes				csio->ccb_h.status = CAM_BDR_SENT;
12761592Srgrimes			else
12771592Srgrimes				csio->ccb_h.status = CAM_CMD_TIMEOUT;
12781592Srgrimes			break;
12791592Srgrimes		}
12801592Srgrimes		if (csio->ccb_h.status != CAM_REQ_CMP) {
12811592Srgrimes			xpt_freeze_devq(csio->ccb_h.path, /*count*/1);
12821592Srgrimes			csio->ccb_h.status |= CAM_DEV_QFRZN;
12831592Srgrimes		}
12841592Srgrimes		if ((bccb->flags & BCCB_RELEASE_SIMQ) != 0)
128525101Sdavidn			ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
128625101Sdavidn		ahafreeccb(aha, bccb);
128725101Sdavidn		xpt_done(ccb);
128825674Sdavidn		break;
128925101Sdavidn	case BMBI_OK:
129025101Sdavidn		/* All completed without incident */
129156668Sshin		/* XXX DO WE NEED TO COPY SENSE BYTES HERE???? XXX */
129256668Sshin		ccb->ccb_h.status |= CAM_REQ_CMP;
129356668Sshin		if ((bccb->flags & BCCB_RELEASE_SIMQ) != 0)
129425101Sdavidn			ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
129525101Sdavidn		ahafreeccb(aha, bccb);
129625101Sdavidn		xpt_done(ccb);
129725101Sdavidn		break;
129825101Sdavidn	}
129925101Sdavidn}
130025101Sdavidn
130125101Sdavidnstatic int
130225101Sdavidnahareset(struct aha_softc* aha, int hard_reset)
130325101Sdavidn{
130425101Sdavidn	struct	 ccb_hdr *ccb_h;
130525101Sdavidn	u_int	 status;
130625101Sdavidn	u_int	 timeout;
130725101Sdavidn	u_int8_t reset_type;
130825101Sdavidn
130925101Sdavidn	if (hard_reset != 0)
131040310Sdes		reset_type = HARD_RESET;
131140310Sdes	else
131225101Sdavidn		reset_type = SOFT_RESET;
131340310Sdes	aha_outb(aha, CONTROL_REG, reset_type);
13141592Srgrimes
131525101Sdavidn	/* Wait 5sec. for Diagnostic start */
13161592Srgrimes	timeout = 5 * 10000;
131774874Smarkm	while (--timeout) {
131874874Smarkm		status = aha_inb(aha, STATUS_REG);
131974874Smarkm		if ((status & DIAG_ACTIVE) != 0)
132074874Smarkm			break;
132174874Smarkm		DELAY(100);
132274874Smarkm	}
132374874Smarkm	if (timeout == 0) {
132474874Smarkm		if (bootverbose)
132574874Smarkm			printf("%s: ahareset - Diagnostic Active failed to "
132674874Smarkm				"assert. status = 0x%x\n", aha_name(aha),
13271592Srgrimes				status);
132829140Stg		return (ETIMEDOUT);
13291592Srgrimes	}
13301592Srgrimes
133117435Spst	/* Wait 10sec. for Diagnostic end */
133225283Sdavidn	timeout = 10 * 10000;
133325283Sdavidn	while (--timeout) {
133425283Sdavidn		status = aha_inb(aha, STATUS_REG);
13356740Sguido		if ((status & DIAG_ACTIVE) == 0)
133625283Sdavidn			break;
13376740Sguido		DELAY(100);
13386740Sguido	}
133925101Sdavidn	if (timeout == 0) {
134025101Sdavidn		panic("%s: ahareset - Diagnostic Active failed to drop. "
134125101Sdavidn		       "status = 0x%x\n", aha_name(aha), status);
134225101Sdavidn		return (ETIMEDOUT);
134336349Ssteve	}
13441592Srgrimes
13451592Srgrimes	/* Wait for the host adapter to become ready or report a failure */
13461592Srgrimes	timeout = 10000;
13471592Srgrimes	while (--timeout) {
13481592Srgrimes		status = aha_inb(aha, STATUS_REG);
13491592Srgrimes		if ((status & (DIAG_FAIL|HA_READY|DATAIN_REG_READY)) != 0)
13501592Srgrimes			break;
13511592Srgrimes		DELAY(100);
13521592Srgrimes	}
13531592Srgrimes	if (timeout == 0) {
135417435Spst		printf("%s: ahareset - Host adapter failed to come ready. "
135517435Spst		       "status = 0x%x\n", aha_name(aha), status);
135617435Spst		return (ETIMEDOUT);
135717435Spst	}
135817435Spst
13591592Srgrimes	/* If the diagnostics failed, tell the user */
13601592Srgrimes	if ((status & DIAG_FAIL) != 0
13611592Srgrimes	 || (status & HA_READY) == 0) {
13621592Srgrimes		printf("%s: ahareset - Adapter failed diagnostics\n",
13631592Srgrimes		       aha_name(aha));
13641592Srgrimes
13651592Srgrimes		if ((status & DATAIN_REG_READY) != 0)
13661592Srgrimes			printf("%s: ahareset - Host Adapter Error "
13671592Srgrimes			       "code = 0x%x\n", aha_name(aha),
13681592Srgrimes			       aha_inb(aha, DATAIN_REG));
13691592Srgrimes		return (ENXIO);
13701592Srgrimes	}
13718696Sdg
13721592Srgrimes	/* If we've allocated mailboxes, initialize them */
13731592Srgrimes	if (aha->init_level > 4)
13741592Srgrimes		ahainitmboxes(aha);
13751592Srgrimes
137625283Sdavidn	/* If we've attached to the XPT, tell it about the event */
137725283Sdavidn	if (aha->path != NULL)
137825283Sdavidn		xpt_async(AC_BUS_RESET, aha->path, NULL);
13791592Srgrimes
138025283Sdavidn	/*
13811592Srgrimes	 * Perform completion processing for all outstanding CCBs.
13821592Srgrimes	 */
13831592Srgrimes	while ((ccb_h = LIST_FIRST(&aha->pending_ccbs)) != NULL) {
13841592Srgrimes		struct aha_ccb *pending_bccb;
13851592Srgrimes
13861592Srgrimes		pending_bccb = (struct aha_ccb *)ccb_h->ccb_bccb_ptr;
13871592Srgrimes		pending_bccb->hccb.ahastat = AHASTAT_HA_SCSI_BUS_RESET;
13881592Srgrimes		ahadone(aha, pending_bccb, BMBI_ERROR);
13891592Srgrimes	}
13901592Srgrimes
13911592Srgrimes	return (0);
13926740Sguido}
13936740Sguido
139417433Spst/*
139517433Spst * Send a command to the adapter.
139676096Smarkm */
139717433Spstint
13981592Srgrimesaha_cmd(struct aha_softc *aha, aha_op_t opcode, u_int8_t *params,
13991592Srgrimes      u_int param_len, u_int8_t *reply_data, u_int reply_len,
140025283Sdavidn      u_int cmd_timeout)
140125283Sdavidn{
140225283Sdavidn	u_int	timeout;
140383308Smikeh	u_int	status;
140483308Smikeh	u_int	intstat;
140525283Sdavidn	u_int	reply_buf_size;
140625283Sdavidn	int	s;
140725283Sdavidn
140883308Smikeh	/* No data returned to start */
140913139Speter	reply_buf_size = reply_len;
14101592Srgrimes	reply_len = 0;
14111592Srgrimes	intstat = 0;
14121592Srgrimes
14131592Srgrimes	aha->command_cmp = 0;
14141592Srgrimes	/*
141525986Sdanny	 * Wait up to 1 sec. for the adapter to become
141625986Sdanny	 * ready to accept commands.
141725986Sdanny	 */
141825986Sdanny	timeout = 10000;
14191592Srgrimes	while (--timeout) {
142025986Sdanny
14211592Srgrimes		status = aha_inb(aha, STATUS_REG);
14221592Srgrimes		if ((status & HA_READY) != 0
142325283Sdavidn		 && (status & CMD_REG_BUSY) == 0)
142413139Speter			break;
14251592Srgrimes		DELAY(100);
14261592Srgrimes	}
14271592Srgrimes	if (timeout == 0) {
14281592Srgrimes		printf("%s: aha_cmd: Timeout waiting for adapter ready, "
14291592Srgrimes		       "status = 0x%x\n", aha_name(aha), status);
143025101Sdavidn		return (ETIMEDOUT);
143125101Sdavidn	}
143225101Sdavidn
14331592Srgrimes	/*
14341592Srgrimes	 * Send the opcode followed by any necessary parameter bytes.
14351592Srgrimes	 */
143625101Sdavidn	aha_outb(aha, COMMAND_REG, opcode);
143725101Sdavidn
143825101Sdavidn	/*
14391592Srgrimes	 * Wait for up to 1sec to get the parameter list sent
14401592Srgrimes	 */
14411592Srgrimes	timeout = 10000;
14421592Srgrimes	while (param_len && --timeout) {
14431592Srgrimes		DELAY(100);
14441592Srgrimes		status = aha_inb(aha, STATUS_REG);
14451592Srgrimes		intstat = aha_inb(aha, INTSTAT_REG);
14461592Srgrimes		if ((intstat & (INTR_PENDING|CMD_COMPLETE))
14471592Srgrimes		 == (INTR_PENDING|CMD_COMPLETE))
14481592Srgrimes			break;
144936612Sjb		if (aha->command_cmp != 0) {
14501592Srgrimes			status = aha->latched_status;
14511592Srgrimes			break;
14521592Srgrimes		}
14531592Srgrimes		if ((status & DATAIN_REG_READY) != 0)
14541592Srgrimes			break;
14551592Srgrimes		if ((status & CMD_REG_BUSY) == 0) {
14561592Srgrimes			aha_outb(aha, COMMAND_REG, *params++);
145731973Simp			param_len--;
14581592Srgrimes		}
14591592Srgrimes	}
14601592Srgrimes	if (timeout == 0) {
14611592Srgrimes		printf("%s: aha_cmd: Timeout sending parameters, "
14621592Srgrimes		       "status = 0x%x\n", aha_name(aha), status);
14631592Srgrimes		return (ETIMEDOUT);
14641592Srgrimes	}
14651592Srgrimes
14661592Srgrimes	/*
14671592Srgrimes	 * For all other commands, we wait for any output data
14681592Srgrimes	 * and the final comand completion interrupt.
14691592Srgrimes	 */
14701592Srgrimes	while (--cmd_timeout) {
14711592Srgrimes
14721592Srgrimes		status = aha_inb(aha, STATUS_REG);
14731592Srgrimes		intstat = aha_inb(aha, INTSTAT_REG);
14741592Srgrimes		if ((intstat & (INTR_PENDING|CMD_COMPLETE))
14751592Srgrimes		 == (INTR_PENDING|CMD_COMPLETE))
14761592Srgrimes			break;
14771592Srgrimes
14781592Srgrimes		if (aha->command_cmp != 0) {
14791592Srgrimes			status = aha->latched_status;
14801592Srgrimes			break;
14811592Srgrimes		}
14821592Srgrimes
14831592Srgrimes		if ((status & DATAIN_REG_READY) != 0) {
14841592Srgrimes			u_int8_t data;
14851592Srgrimes
14861592Srgrimes			data = aha_inb(aha, DATAIN_REG);
14871592Srgrimes			if (reply_len < reply_buf_size) {
14881592Srgrimes				*reply_data++ = data;
14891592Srgrimes			} else {
14901592Srgrimes				printf("%s: aha_cmd - Discarded reply data byte "
14911592Srgrimes				       "for opcode 0x%x\n", aha_name(aha),
14921592Srgrimes				       opcode);
14931592Srgrimes			}
14941592Srgrimes			reply_len++;
14951592Srgrimes		}
14961592Srgrimes
14971592Srgrimes		DELAY(100);
14981592Srgrimes	}
14996740Sguido	if (timeout == 0) {
15008240Swollman		printf("%s: aha_cmd: Timeout waiting for reply data and "
15018240Swollman		       "command complete.\n%s: status = 0x%x, intstat = 0x%x, "
15026740Sguido		       "reply_len = %d\n", aha_name(aha), aha_name(aha), status,
150317433Spst		       intstat, reply_len);
15041592Srgrimes		return (ETIMEDOUT);
15051592Srgrimes	}
15061592Srgrimes
15071592Srgrimes	/*
15081592Srgrimes	 * Clear any pending interrupts.  Block interrupts so our
15091592Srgrimes	 * interrupt handler is not re-entered.
15101592Srgrimes	 */
15111592Srgrimes	s = splcam();
15121592Srgrimes	aha_intr(aha);
15131592Srgrimes	splx(s);
15141592Srgrimes
15151592Srgrimes	/*
15161592Srgrimes	 * If the command was rejected by the controller, tell the caller.
15171592Srgrimes	 */
15181592Srgrimes	if ((status & CMD_INVALID) != 0) {
15191592Srgrimes		if (bootverbose)
15201592Srgrimes			printf("%s: Invalid Command 0x%x\n", aha_name(aha),
15211592Srgrimes				opcode);
152217433Spst		/*
15231592Srgrimes		 * Some early adapters may not recover properly from
15241592Srgrimes		 * an invalid command.  If it appears that the controller
15251592Srgrimes		 * has wedged (i.e. status was not cleared by our interrupt
15261592Srgrimes		 * reset above), perform a soft reset.
15271592Srgrimes      		 */
15281592Srgrimes		DELAY(1000);
15291592Srgrimes		status = aha_inb(aha, STATUS_REG);
15301592Srgrimes		if ((status & (CMD_INVALID|STATUS_REG_RSVD|DATAIN_REG_READY|
15311592Srgrimes			      CMD_REG_BUSY|DIAG_FAIL|DIAG_ACTIVE)) != 0
15321592Srgrimes		 || (status & (HA_READY|INIT_REQUIRED))
15331592Srgrimes		  != (HA_READY|INIT_REQUIRED)) {
15341592Srgrimes			ahareset(aha, /*hard_reset*/FALSE);
15351592Srgrimes		}
15361592Srgrimes		return (EINVAL);
15371592Srgrimes	}
15381592Srgrimes
15391592Srgrimes
15401592Srgrimes	if (param_len > 0) {
15411592Srgrimes		/* The controller did not accept the full argument list */
15421592Srgrimes	 	return (E2BIG);
15431592Srgrimes	}
15441592Srgrimes
15451592Srgrimes	if (reply_len != reply_buf_size) {
15461592Srgrimes		/* Too much or too little data received */
15471592Srgrimes		return (EMSGSIZE);
15481592Srgrimes	}
15491592Srgrimes
15501592Srgrimes	/* We were successful */
15511592Srgrimes	return (0);
15521592Srgrimes}
15531592Srgrimes
15541592Srgrimesstatic int
15551592Srgrimesahainitmboxes(struct aha_softc *aha)
15561592Srgrimes{
15571592Srgrimes	int error;
155882792Sache	init_24b_mbox_params_t init_mbox;
15591592Srgrimes
15601592Srgrimes	bzero(aha->in_boxes, sizeof(aha_mbox_in_t) * aha->num_boxes);
15611592Srgrimes	bzero(aha->out_boxes, sizeof(aha_mbox_out_t) * aha->num_boxes);
15621592Srgrimes	aha->cur_inbox = aha->in_boxes;
15631592Srgrimes	aha->last_inbox = aha->in_boxes + aha->num_boxes - 1;
15641592Srgrimes	aha->cur_outbox = aha->out_boxes;
15651592Srgrimes	aha->last_outbox = aha->out_boxes + aha->num_boxes - 1;
15661592Srgrimes
15671592Srgrimes	/* Tell the adapter about them */
15681592Srgrimes	init_mbox.num_mboxes = aha->num_boxes;
15691592Srgrimes	ahautoa24(aha->mailbox_physbase, init_mbox.base_addr);
15701592Srgrimes	error = aha_cmd(aha, BOP_INITIALIZE_MBOX, (u_int8_t *)&init_mbox,
15711592Srgrimes		       /*parmlen*/sizeof(init_mbox), /*reply_buf*/NULL,
15721592Srgrimes		       /*reply_len*/0, DEFAULT_CMD_TIMEOUT);
15731592Srgrimes
15741592Srgrimes	if (error != 0)
15751592Srgrimes		printf("ahainitmboxes: Initialization command failed\n");
15761592Srgrimes	return (error);
15771592Srgrimes}
15781592Srgrimes
15791592Srgrimes/*
15801592Srgrimes * Update the XPT's idea of the negotiated transfer
15811592Srgrimes * parameters for a particular target.
15821592Srgrimes */
15831592Srgrimesstatic void
15841592Srgrimesahafetchtransinfo(struct aha_softc *aha, struct ccb_trans_settings* cts)
15851592Srgrimes{
15861592Srgrimes	setup_data_t	setup_info;
15871592Srgrimes	u_int		target;
15881592Srgrimes	u_int		targ_offset;
15891592Srgrimes	u_int		sync_period;
15901592Srgrimes	int		error;
15911592Srgrimes	u_int8_t	param;
15921592Srgrimes	targ_syncinfo_t	sync_info;
15931592Srgrimes
159456668Sshin	target = cts->ccb_h.target_id;
159556668Sshin	targ_offset = (target & 0x7);
15961592Srgrimes
15971592Srgrimes	/*
15981592Srgrimes	 * Inquire Setup Information.  This command retreives the
15991592Srgrimes	 * Wide negotiation status for recent adapters as well as
16001592Srgrimes	 * the sync info for older models.
16011592Srgrimes	 */
160256668Sshin	param = sizeof(setup_info);
160356668Sshin	error = aha_cmd(aha, BOP_INQUIRE_SETUP_INFO, &param, /*paramlen*/1,
16041592Srgrimes		       (u_int8_t*)&setup_info, sizeof(setup_info),
16051592Srgrimes		       DEFAULT_CMD_TIMEOUT);
160656668Sshin
16071592Srgrimes	if (error != 0) {
16081592Srgrimes		printf("%s: ahafetchtransinfo - Inquire Setup Info Failed\n",
16091592Srgrimes		       aha_name(aha));
16101592Srgrimes		return;
16111592Srgrimes	}
16121592Srgrimes
16131592Srgrimes	sync_info = setup_info.syncinfo[targ_offset];
161456668Sshin
161556668Sshin	if (sync_info.sync == 0)
16161592Srgrimes		cts->sync_offset = 0;
16171592Srgrimes	else
16181592Srgrimes		cts->sync_offset = sync_info.offset;
161956668Sshin
16201592Srgrimes	cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
16218240Swollman
16228240Swollman	sync_period = 2000 + (500 * sync_info.period);
16238240Swollman
16248240Swollman	/* Convert ns value to standard SCSI sync rate */
16258240Swollman	if (cts->sync_offset != 0)
16268240Swollman		cts->sync_period = scsi_calc_syncparam(sync_period);
16278240Swollman	else
16288240Swollman		cts->sync_period = 0;
16298240Swollman
16308240Swollman	cts->valid = CCB_TRANS_SYNC_RATE_VALID
16318240Swollman		   | CCB_TRANS_SYNC_OFFSET_VALID
16328240Swollman		   | CCB_TRANS_BUS_WIDTH_VALID;
16338240Swollman        xpt_async(AC_TRANSFER_NEG, cts->ccb_h.path, cts);
16348240Swollman}
16358240Swollman
16368240Swollmanstatic void
16378240Swollmanahamapmboxes(void *arg, bus_dma_segment_t *segs, int nseg, int error)
16381592Srgrimes{
16391592Srgrimes	struct aha_softc* aha;
16401592Srgrimes
16411592Srgrimes	aha = (struct aha_softc*)arg;
16421592Srgrimes	aha->mailbox_physbase = segs->ds_addr;
16431592Srgrimes}
16441592Srgrimes
16451592Srgrimesstatic void
16461592Srgrimesahamapccbs(void *arg, bus_dma_segment_t *segs, int nseg, int error)
16471592Srgrimes{
16481592Srgrimes	struct aha_softc* aha;
16491592Srgrimes
16501592Srgrimes	aha = (struct aha_softc*)arg;
16511592Srgrimes	aha->aha_ccb_physbase = segs->ds_addr;
16521592Srgrimes}
16531592Srgrimes
16541592Srgrimesstatic void
16551592Srgrimesahamapsgs(void *arg, bus_dma_segment_t *segs, int nseg, int error)
16561592Srgrimes{
16571592Srgrimes
16581592Srgrimes	struct aha_softc* aha;
16591592Srgrimes
16601592Srgrimes	aha = (struct aha_softc*)arg;
166131973Simp	SLIST_FIRST(&aha->sg_maps)->sg_physaddr = segs->ds_addr;
16621592Srgrimes}
166331973Simp
16641592Srgrimesstatic void
166556668Sshinahapoll(struct cam_sim *sim)
166656668Sshin{
166712532Sguido}
166812532Sguido
16691592Srgrimesvoid
167012532Sguidoahatimeout(void *arg)
167112532Sguido{
167212532Sguido	struct aha_ccb	*bccb;
167312532Sguido	union  ccb	*ccb;
167412532Sguido	struct aha_softc *aha;
167512532Sguido	int		 s;
167612532Sguido	u_int32_t	paddr;
167712532Sguido
16781592Srgrimes	bccb = (struct aha_ccb *)arg;
16791592Srgrimes	ccb = bccb->ccb;
16801592Srgrimes	aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr;
16811592Srgrimes	xpt_print_path(ccb->ccb_h.path);
16821592Srgrimes	printf("CCB 0x%x - timed out\n", (intptr_t)bccb);
16831592Srgrimes
16841592Srgrimes	s = splcam();
16851592Srgrimes
168656668Sshin	if ((bccb->flags & BCCB_ACTIVE) == 0) {
168756668Sshin		xpt_print_path(ccb->ccb_h.path);
168817435Spst		printf("CCB 0x%x - timed out CCB already completed\n",
16891592Srgrimes		       (intptr_t)bccb);
16901592Srgrimes		splx(s);
169156668Sshin		return;
16921592Srgrimes	}
16931592Srgrimes
16941592Srgrimes	/*
16951592Srgrimes	 * In order to simplify the recovery process, we ask the XPT
16961592Srgrimes	 * layer to halt the queue of new transactions and we traverse
16971592Srgrimes	 * the list of pending CCBs and remove their timeouts. This
16981592Srgrimes	 * means that the driver attempts to clear only one error
16991592Srgrimes	 * condition at a time.  In general, timeouts that occur
17001592Srgrimes	 * close together are related anyway, so there is no benefit
17011592Srgrimes	 * in attempting to handle errors in parrallel.  Timeouts will
17021592Srgrimes	 * be reinstated when the recovery process ends.
17031592Srgrimes	 */
17041592Srgrimes	if ((bccb->flags & BCCB_DEVICE_RESET) == 0) {
17051592Srgrimes		struct ccb_hdr *ccb_h;
17061592Srgrimes
17071592Srgrimes		if ((bccb->flags & BCCB_RELEASE_SIMQ) == 0) {
170856668Sshin			xpt_freeze_simq(aha->sim, /*count*/1);
170956668Sshin			bccb->flags |= BCCB_RELEASE_SIMQ;
171056668Sshin		}
171156668Sshin
171256668Sshin		ccb_h = LIST_FIRST(&aha->pending_ccbs);
171356668Sshin		while (ccb_h != NULL) {
171456668Sshin			struct aha_ccb *pending_bccb;
17151592Srgrimes
17161592Srgrimes			pending_bccb = (struct aha_ccb *)ccb_h->ccb_bccb_ptr;
17171592Srgrimes			untimeout(ahatimeout, pending_bccb, ccb_h->timeout_ch);
17181592Srgrimes			ccb_h = LIST_NEXT(ccb_h, sim_links.le);
171956668Sshin		}
17201592Srgrimes	}
17211592Srgrimes
17221592Srgrimes	if ((bccb->flags & BCCB_DEVICE_RESET) != 0
17231592Srgrimes	 || aha->cur_outbox->action_code != BMBO_FREE) {
17241592Srgrimes		/*
17251592Srgrimes		 * Try a full host adapter/SCSI bus reset.
17261592Srgrimes		 * We do this only if we have already attempted
17271592Srgrimes		 * to clear the condition with a BDR, or we cannot
17281592Srgrimes		 * attempt a BDR for lack of mailbox resources.
17291592Srgrimes		 */
17301592Srgrimes		ccb->ccb_h.status = CAM_CMD_TIMEOUT;
17311592Srgrimes		ahareset(aha, /*hardreset*/TRUE);
17321592Srgrimes		printf("%s: No longer in timeout\n", aha_name(aha));
17331592Srgrimes	} else {
17341592Srgrimes		/*
17351592Srgrimes		 * Send a Bus Device Reset message:
17361592Srgrimes		 * The target that is holding up the bus may not
17378240Swollman		 * be the same as the one that triggered this timeout
17381592Srgrimes		 * (different commands have different timeout lengths),
17391592Srgrimes		 * but we have no way of determining this from our
17401592Srgrimes		 * timeout handler.  Our strategy here is to queue a
17411592Srgrimes		 * BDR message to the target of the timed out command.
17428240Swollman		 * If this fails, we'll get another timeout 2 seconds
17431592Srgrimes		 * later which will attempt a bus reset.
17441592Srgrimes		 */
17458240Swollman		bccb->flags |= BCCB_DEVICE_RESET;
17468240Swollman		ccb->ccb_h.timeout_ch = timeout(ahatimeout, (caddr_t)bccb, 2 * hz);
17471592Srgrimes		aha->recovery_bccb->hccb.opcode = INITIATOR_BUS_DEV_RESET;
174870205Sdan
174970205Sdan		/* No Data Transfer */
17508240Swollman		aha->recovery_bccb->hccb.datain = TRUE;
175170205Sdan		aha->recovery_bccb->hccb.dataout = TRUE;
17521592Srgrimes		aha->recovery_bccb->hccb.ahastat = 0;
17531592Srgrimes		aha->recovery_bccb->hccb.sdstat = 0;
17541592Srgrimes		aha->recovery_bccb->hccb.target = ccb->ccb_h.target_id;
17551592Srgrimes
17561592Srgrimes		/* Tell the adapter about this command */
17571592Srgrimes		paddr = ahaccbvtop(aha, aha->recovery_bccb);
17581592Srgrimes		ahautoa24(paddr, aha->cur_outbox->ccb_addr);
17591592Srgrimes		aha->cur_outbox->action_code = BMBO_START;
17601592Srgrimes		aha_outb(aha, COMMAND_REG, BOP_START_MBOX);
17611592Srgrimes		ahanextoutbox(aha);
17621592Srgrimes	}
17631592Srgrimes
17641592Srgrimes	splx(s);
17651592Srgrimes}
17661592Srgrimes