aha.c revision 163816
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 *      aha 1542A/1542B/1542C/1542CF/1542CP	aha_isa.c
61592Srgrimes *      aha 1640			aha_mca.c
71592Srgrimes */
81592Srgrimes/*-
91592Srgrimes * Copyright (c) 1998 M. Warner Losh.
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 * 2. Redistributions in binary form must reproduce the above copyright
181592Srgrimes *    notice, this list of conditions and the following disclaimer in the
191592Srgrimes *    documentation and/or other materials provided with the distribution.
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
251592Srgrimes * FOR 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 * Derived from bt.c written by:
3417478Smarkm *
351592Srgrimes * Copyright (c) 1998 Justin T. Gibbs.
361592Srgrimes * All rights reserved.
371592Srgrimes *
381592Srgrimes * Redistribution and use in source and binary forms, with or without
391592Srgrimes * modification, are permitted provided that the following conditions
4017478Smarkm * are met:
411592Srgrimes * 1. Redistributions of source code must retain the above copyright
4231329Scharnier *    notice, this list of conditions, and the following disclaimer,
4317478Smarkm *    without modification, immediately at the beginning of the file.
441592Srgrimes * 2. The name of the author may not be used to endorse or promote products
4531329Scharnier *    derived from this software without specific prior written permission.
4631329Scharnier *
4750476Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
481592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
491592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
501592Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
511592Srgrimes * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
521592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
531592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
541592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5566907Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
561592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5766907Swollman * SUCH DAMAGE.
5866907Swollman */
591592Srgrimes
601592Srgrimes#include <sys/cdefs.h>
611592Srgrimes__FBSDID("$FreeBSD: head/sys/dev/aha/aha.c 163816 2006-10-31 05:53:29Z mjacob $");
621592Srgrimes
631592Srgrimes#include <sys/param.h>
648240Swollman#include <sys/bus.h>
651592Srgrimes#include <sys/systm.h>
661592Srgrimes#include <sys/malloc.h>
671592Srgrimes#include <sys/kernel.h>
681592Srgrimes#include <sys/lock.h>
691592Srgrimes#include <sys/mutex.h>
701592Srgrimes
711592Srgrimes#include <machine/bus.h>
721592Srgrimes
731592Srgrimes#include <cam/cam.h>
741592Srgrimes#include <cam/cam_ccb.h>
751592Srgrimes#include <cam/cam_sim.h>
761592Srgrimes#include <cam/cam_xpt_sim.h>
771592Srgrimes#include <cam/cam_debug.h>
781592Srgrimes
791592Srgrimes#include <cam/scsi/scsi_message.h>
8025187Sdavidn
8188763Sache#include <dev/aha/ahareg.h>
821592Srgrimes
831592Srgrimes#define	PRVERB(x) do { if (bootverbose) device_printf x; } while (0)
841592Srgrimes
851592Srgrimes/* Macro to determine that a rev is potentially a new valid one
861592Srgrimes * so that the driver doesn't keep breaking on new revs as it
871592Srgrimes * did for the CF and CP.
881592Srgrimes */
8913139Speter#define PROBABLY_NEW_BOARD(REV) (REV > 0x43 && REV < 0x56)
9025101Sdavidn
9125101Sdavidn/* MailBox Management functions */
9225101Sdavidnstatic __inline void	ahanextinbox(struct aha_softc *aha);
931592Srgrimesstatic __inline void	ahanextoutbox(struct aha_softc *aha);
9474874Smarkm
9551433Smarkm#define aha_name(aha)	device_get_nameunit(aha->dev)
9651433Smarkm
9751433Smarkmstatic __inline void
981592Srgrimesahanextinbox(struct aha_softc *aha)
991592Srgrimes{
1001592Srgrimes	if (aha->cur_inbox == aha->last_inbox)
1011592Srgrimes		aha->cur_inbox = aha->in_boxes;
1021592Srgrimes	else
10325165Sdavidn		aha->cur_inbox++;
10425165Sdavidn}
1051592Srgrimes
1061592Srgrimesstatic __inline void
1071592Srgrimesahanextoutbox(struct aha_softc *aha)
1081592Srgrimes{
10956668Sshin	if (aha->cur_outbox == aha->last_outbox)
11056668Sshin		aha->cur_outbox = aha->out_boxes;
11156668Sshin	else
11256668Sshin		aha->cur_outbox++;
11356668Sshin}
1141592Srgrimes
11515196Sdg#define ahautoa24(u,s3)			\
1161592Srgrimes	(s3)[0] = ((u) >> 16) & 0xff;	\
117109742Syar	(s3)[1] = ((u) >> 8) & 0xff;	\
118110037Syar	(s3)[2] = (u) & 0xff;
1191592Srgrimes
1201592Srgrimes#define aha_a24tou(s3) \
121110036Syar	(((s3)[0] << 16) | ((s3)[1] << 8) | (s3)[2])
12276096Smarkm
1231592Srgrimes/* CCB Mangement functions */
1241592Srgrimesstatic __inline uint32_t		ahaccbvtop(struct aha_softc *aha,
1251592Srgrimes						  struct aha_ccb *accb);
1269933Spststatic __inline struct aha_ccb*		ahaccbptov(struct aha_softc *aha,
12717435Spst						  uint32_t ccb_addr);
12820042Storstenb
1291592Srgrimesstatic __inline uint32_t
13017435Spstahaccbvtop(struct aha_softc *aha, struct aha_ccb *accb)
131102311Syar{
1326740Sguido	return (aha->aha_ccb_physbase
1336740Sguido	      + (uint32_t)((caddr_t)accb - (caddr_t)aha->aha_ccb_array));
1341592Srgrimes}
1351592Srgrimesstatic __inline struct aha_ccb *
1361592Srgrimesahaccbptov(struct aha_softc *aha, uint32_t ccb_addr)
1371592Srgrimes{
1381592Srgrimes	return (aha->aha_ccb_array +
1391592Srgrimes	      + ((struct aha_ccb*)(uintptr_t)ccb_addr -
14070102Sphk	         (struct aha_ccb*)(uintptr_t)aha->aha_ccb_physbase));
14170102Sphk}
14282460Snik
14382796Ssheldonhstatic struct aha_ccb*	ahagetccb(struct aha_softc *aha);
14499195Smdoddstatic __inline void	ahafreeccb(struct aha_softc *aha, struct aha_ccb *accb);
145101537Syarstatic void		ahaallocccbs(struct aha_softc *aha);
14682460Snikstatic bus_dmamap_callback_t ahaexecuteccb;
14789935Syarstatic void		ahadone(struct aha_softc *aha, struct aha_ccb *accb,
1481592Srgrimes			       aha_mbi_comp_code_t comp_code);
1491592Srgrimes
1501592Srgrimes/* Host adapter command functions */
1511592Srgrimesstatic int	ahareset(struct aha_softc* aha, int hard_reset);
1521592Srgrimes
1531592Srgrimes/* Initialization functions */
1541592Srgrimesstatic int			ahainitmboxes(struct aha_softc *aha);
1551592Srgrimesstatic bus_dmamap_callback_t	ahamapmboxes;
1561592Srgrimesstatic bus_dmamap_callback_t	ahamapccbs;
15727650Sdavidnstatic bus_dmamap_callback_t	ahamapsgs;
15878153Sdd
15978153Sdd/* Transfer Negotiation Functions */
16025283Sdavidnstatic void ahafetchtransinfo(struct aha_softc *aha,
16125283Sdavidn			     struct ccb_trans_settings *cts);
16225283Sdavidn
16325283Sdavidn/* CAM SIM entry points */
16425283Sdavidn#define ccb_accb_ptr spriv_ptr0
16557124Sshin#define ccb_aha_ptr spriv_ptr1
16625283Sdavidnstatic void	ahaaction(struct cam_sim *sim, union ccb *ccb);
16725283Sdavidnstatic void	ahapoll(struct cam_sim *sim);
16825283Sdavidn
16925283Sdavidn/* Our timeout handler */
17025283Sdavidnstatic timeout_t ahatimeout;
17125283Sdavidn
17225283Sdavidn/* Exported functions */
17325283Sdavidnvoid
17445422Sbrianaha_alloc(struct aha_softc *aha, int unit, bus_space_tag_t tag,
1756740Sguido  bus_space_handle_t bsh)
17617435Spst{
17717435Spst
17817435Spst	SLIST_INIT(&aha->free_aha_ccbs);
17917435Spst	LIST_INIT(&aha->pending_ccbs);
18074874Smarkm	SLIST_INIT(&aha->sg_maps);
18190148Simp	aha->unit = unit;
18274874Smarkm	aha->tag = tag;
18388763Sache	aha->bsh = bsh;
18479469Smarkm	aha->ccb_sg_opcode = INITIATOR_SG_CCB_WRESID;
18579469Smarkm	aha->ccb_ccb_opcode = INITIATOR_CCB_WRESID;
18679469Smarkm}
18788763Sache
18817478Smarkmvoid
18917483Sjulianaha_free(struct aha_softc *aha)
19017483Sjulian{
1911592Srgrimes	switch (aha->init_level) {
19274470Sjlemon	default:
19374470Sjlemon	case 8:
19474470Sjlemon	{
19574470Sjlemon		struct sg_map_node *sg_map;
19674470Sjlemon
19774470Sjlemon		while ((sg_map = SLIST_FIRST(&aha->sg_maps))!= NULL) {
19874470Sjlemon			SLIST_REMOVE_HEAD(&aha->sg_maps, links);
1991592Srgrimes			bus_dmamap_unload(aha->sg_dmat, sg_map->sg_dmamap);
2001592Srgrimes			bus_dmamem_free(aha->sg_dmat, sg_map->sg_vaddr,
2011592Srgrimes			    sg_map->sg_dmamap);
2021592Srgrimes			free(sg_map, M_DEVBUF);
2031592Srgrimes		}
2041592Srgrimes		bus_dma_tag_destroy(aha->sg_dmat);
2051592Srgrimes	}
2061592Srgrimes	case 7:
2071592Srgrimes		bus_dmamap_unload(aha->ccb_dmat, aha->ccb_dmamap);
2081592Srgrimes	case 6:
2091592Srgrimes		bus_dmamap_destroy(aha->ccb_dmat, aha->ccb_dmamap);
21013139Speter		bus_dmamem_free(aha->ccb_dmat, aha->aha_ccb_array,
2111592Srgrimes		    aha->ccb_dmamap);
2121592Srgrimes	case 5:
21313139Speter		bus_dma_tag_destroy(aha->ccb_dmat);
2141592Srgrimes	case 4:
2151592Srgrimes		bus_dmamap_unload(aha->mailbox_dmat, aha->mailbox_dmamap);
2161592Srgrimes	case 3:
2171592Srgrimes		bus_dmamem_free(aha->mailbox_dmat, aha->in_boxes,
2181592Srgrimes		    aha->mailbox_dmamap);
2191592Srgrimes		bus_dmamap_destroy(aha->mailbox_dmat, aha->mailbox_dmamap);
2201592Srgrimes	case 2:
2211592Srgrimes		bus_dma_tag_destroy(aha->buffer_dmat);
2221592Srgrimes	case 1:
2231592Srgrimes		bus_dma_tag_destroy(aha->mailbox_dmat);
2241592Srgrimes	case 0:
2251592Srgrimes		break;
2261592Srgrimes	}
2271592Srgrimes}
2281592Srgrimes
2291592Srgrimes/*
2301592Srgrimes * Probe the adapter and verify that the card is an Adaptec.
2311592Srgrimes */
2321592Srgrimesint
2331592Srgrimesaha_probe(struct aha_softc* aha)
2341592Srgrimes{
2351592Srgrimes	u_int	 status;
23625283Sdavidn	u_int	 intstat;
23790148Simp	int	 error;
23890148Simp	board_id_data_t	board_id;
23925283Sdavidn
24090148Simp	/*
24190148Simp	 * See if the three I/O ports look reasonable.
24290148Simp	 * Touch the minimal number of registers in the
243109893Syar	 * failure case.
24490148Simp	 */
24590148Simp	status = aha_inb(aha, STATUS_REG);
24690148Simp	if ((status == 0) ||
24790148Simp	    (status & (DIAG_ACTIVE|CMD_REG_BUSY | STATUS_REG_RSVD)) != 0) {
24890148Simp		PRVERB((aha->dev, "status reg test failed %x\n", status));
249101537Syar		return (ENXIO);
25090148Simp	}
25190148Simp
25290148Simp	intstat = aha_inb(aha, INTSTAT_REG);
25390148Simp	if ((intstat & INTSTAT_REG_RSVD) != 0) {
2541592Srgrimes		PRVERB((aha->dev, "Failed Intstat Reg Test\n"));
25590148Simp		return (ENXIO);
25690148Simp	}
25790148Simp
25890148Simp	/*
259100486Syar	 * Looking good so far.  Final test is to reset the
260120059Sume	 * adapter and fetch the board ID and ensure we aren't
2611592Srgrimes	 * looking at a BusLogic.
2621592Srgrimes	 */
26390148Simp	if ((error = ahareset(aha, /*hard_reset*/TRUE)) != 0) {
2641592Srgrimes		PRVERB((aha->dev, "Failed Reset\n"));
2651592Srgrimes		return (ENXIO);
2661592Srgrimes	}
2671592Srgrimes
2681592Srgrimes	/*
2691592Srgrimes	 * Get the board ID.  We use this to see if we're dealing with
2701592Srgrimes	 * a buslogic card or an aha card (or clone).
2711592Srgrimes	 */
2721592Srgrimes	error = aha_cmd(aha, AOP_INQUIRE_BOARD_ID, NULL, /*parmlen*/0,
2731592Srgrimes	    (uint8_t*)&board_id, sizeof(board_id), DEFAULT_CMD_TIMEOUT);
2741592Srgrimes	if (error != 0) {
2751592Srgrimes		PRVERB((aha->dev, "INQUIRE failed %x\n", error));
27690148Simp		return (ENXIO);
2771592Srgrimes	}
2781592Srgrimes	aha->fw_major = board_id.firmware_rev_major;
2791592Srgrimes	aha->fw_minor = board_id.firmware_rev_minor;
2801592Srgrimes	aha->boardid = board_id.board_type;
28156668Sshin
28256668Sshin	/*
283109742Syar	 * The Buslogic cards have an id of either 0x41 or 0x42.  So
28456668Sshin	 * if those come up in the probe, we test the geometry register
28589935Syar	 * of the board.  Adaptec boards that are this old will not have
2861592Srgrimes	 * this register, and return 0xff, while buslogic cards will return
28736105Sache	 * something different.
28889935Syar	 *
28989935Syar	 * It appears that for reasons unknow, for the for the
29036105Sache	 * aha-1542B cards, we need to wait a little bit before trying
29113139Speter	 * to read the geometry register.  I picked 10ms since we have
2921592Srgrimes	 * reports that a for loop to 1000 did the trick, and this
2931592Srgrimes	 * errs on the side of conservatism.  Besides, no one will
2941592Srgrimes	 * notice a 10mS delay here, even the 1542B card users :-)
2951592Srgrimes	 *
2961592Srgrimes	 * Some compatible cards return 0 here.  Some cards also
2971592Srgrimes	 * seem to return 0x7f.
2981592Srgrimes	 *
29913139Speter	 * XXX I'm not sure how this will impact other cloned cards
3001592Srgrimes	 *
3016740Sguido	 * This really should be replaced with the esetup command, since
302110037Syar	 * that appears to be more reliable.  This becomes more and more
303110037Syar	 * true over time as we discover more cards that don't read the
3041592Srgrimes	 * geometry register consistantly.
305100717Syar	 */
306120059Sume	if (aha->boardid <= 0x42) {
30715196Sdg		/* Wait 10ms before reading */
30815196Sdg		DELAY(10000);
309100717Syar		status = aha_inb(aha, GEOMETRY_REG);
310120059Sume		if (status != 0xff && status != 0x00 && status != 0x7f) {
311100717Syar			PRVERB((aha->dev, "Geometry Register test failed %#x\n",
312100717Syar				status));
313100717Syar			return (ENXIO);
314100717Syar		}
315100717Syar	}
316100717Syar
317100717Syar	return (0);
318100717Syar}
319100717Syar
320100717Syar/*
3211592Srgrimes * Pull the boards setup information and record it in our softc.
32276096Smarkm */
3231592Srgrimesint
3241592Srgrimesaha_fetch_adapter_info(struct aha_softc *aha)
325100717Syar{
326100717Syar	setup_data_t	setup_info;
327100717Syar	config_data_t config_data;
328100717Syar	uint8_t length_param;
32970102Sphk	int	 error;
33070102Sphk	struct	aha_extbios extbios;
33170102Sphk
33270102Sphk	switch (aha->boardid) {
333110037Syar	case BOARD_1540_16HEAD_BIOS:
334110037Syar		snprintf(aha->model, sizeof(aha->model), "1540 16 head BIOS");
335110037Syar		break;
336110037Syar	case BOARD_1540_64HEAD_BIOS:
3371592Srgrimes		snprintf(aha->model, sizeof(aha->model), "1540 64 head BIOS");
3381592Srgrimes		break;
3391592Srgrimes	case BOARD_1542:
3401592Srgrimes		snprintf(aha->model, sizeof(aha->model), "1540/1542 64 head BIOS");
341101537Syar		break;
342101537Syar	case BOARD_1640:
343101537Syar		snprintf(aha->model, sizeof(aha->model), "1640");
344101537Syar		break;
345100717Syar	case BOARD_1740:
346100717Syar		snprintf(aha->model, sizeof(aha->model), "1740A/1742A/1744");
347100717Syar		break;
348100717Syar	case BOARD_1542C:
349100717Syar		snprintf(aha->model, sizeof(aha->model), "1542C");
350100717Syar		break;
351100717Syar	case BOARD_1542CF:
352100717Syar		snprintf(aha->model, sizeof(aha->model), "1542CF");
353100717Syar		break;
354100717Syar	case BOARD_1542CP:
355100717Syar		snprintf(aha->model, sizeof(aha->model), "1542CP");
356100717Syar		break;
357100717Syar	default:
358100717Syar		snprintf(aha->model, sizeof(aha->model), "Unknown");
359100717Syar		break;
360100717Syar	}
361109742Syar	/*
362109742Syar	 * If we are a new type of 1542 board (anything newer than a 1542C)
363109742Syar	 * then disable the extended bios so that the
364109742Syar	 * mailbox interface is unlocked.
36570102Sphk	 * This is also true for the 1542B Version 3.20. First Adaptec
36670102Sphk	 * board that supports >1Gb drives.
36770102Sphk	 * No need to check the extended bios flags as some of the
36870102Sphk	 * extensions that cause us problems are not flagged in that byte.
36917435Spst	 */
37017435Spst	if (PROBABLY_NEW_BOARD(aha->boardid) ||
3719933Spst		(aha->boardid == 0x41
3729933Spst		&& aha->fw_major == 0x31 &&
3736740Sguido		aha->fw_minor >= 0x34)) {
37417435Spst		error = aha_cmd(aha, AOP_RETURN_EXT_BIOS_INFO, NULL,
3756740Sguido		    /*paramlen*/0, (u_char *)&extbios, sizeof(extbios),
37617435Spst		    DEFAULT_CMD_TIMEOUT);
37717435Spst		if (error != 0) {
37817435Spst			device_printf(aha->dev,
37917435Spst			    "AOP_RETURN_EXT_BIOS_INFO - Failed.");
38017435Spst			return (error);
38117435Spst		}
38217435Spst		error = aha_cmd(aha, AOP_MBOX_IF_ENABLE, (uint8_t *)&extbios,
383100717Syar		    /*paramlen*/2, NULL, 0, DEFAULT_CMD_TIMEOUT);
384100717Syar		if (error != 0) {
385100717Syar			device_printf(aha->dev, "AOP_MBOX_IF_ENABLE - Failed.");
386100717Syar			return (error);
38717435Spst		}
38817435Spst	}
3891592Srgrimes	if (aha->boardid < 0x41)
3901592Srgrimes		device_printf(aha->dev, "Warning: aha-1542A won't work.\n");
3911592Srgrimes
3921592Srgrimes	aha->max_sg = 17;		/* Need >= 17 to do 64k I/O */
3931592Srgrimes	aha->diff_bus = 0;
3941592Srgrimes	aha->extended_lun = 0;
3951592Srgrimes	aha->extended_trans = 0;
3961592Srgrimes	aha->max_ccbs = 16;
3971592Srgrimes	/* Determine Sync/Wide/Disc settings */
3981592Srgrimes	length_param = sizeof(setup_info);
3991592Srgrimes	error = aha_cmd(aha, AOP_INQUIRE_SETUP_INFO, &length_param,
400100717Syar	    /*paramlen*/1, (uint8_t*)&setup_info, sizeof(setup_info),
401100717Syar	    DEFAULT_CMD_TIMEOUT);
40220042Storstenb	if (error != 0) {
4031592Srgrimes		device_printf(aha->dev, "aha_fetch_adapter_info - Failed "
4041592Srgrimes		    "Get Setup Info\n");
405100720Syar		return (error);
4061592Srgrimes	}
4071592Srgrimes	if (setup_info.initiate_sync != 0) {
408102311Syar		aha->sync_permitted = ALL_TARGETS;
409102311Syar	}
410102311Syar	aha->disc_permitted = ALL_TARGETS;
411102311Syar
4121592Srgrimes	/* We need as many mailboxes as we can have ccbs */
4131592Srgrimes	aha->num_boxes = aha->max_ccbs;
4141592Srgrimes
4151592Srgrimes	/* Determine our SCSI ID */
4161592Srgrimes	error = aha_cmd(aha, AOP_INQUIRE_CONFIG, NULL, /*parmlen*/0,
41715196Sdg	    (uint8_t*)&config_data, sizeof(config_data), DEFAULT_CMD_TIMEOUT);
41825283Sdavidn	if (error != 0) {
41925283Sdavidn		device_printf(aha->dev,
42025283Sdavidn		    "aha_fetch_adapter_info - Failed Get Config\n");
4211592Srgrimes		return (error);
42215196Sdg	}
42315196Sdg	aha->scsi_id = config_data.scsi_id;
42415196Sdg	return (0);
42515196Sdg}
42615196Sdg
42715196Sdg/*
42815196Sdg * Start the board, ready for normal operation
42915196Sdg */
430120059Sumeint
431120059Sumeaha_init(struct aha_softc* aha)
432120059Sume{
43315196Sdg	/* Announce the Adapter */
43415196Sdg	device_printf(aha->dev, "AHA-%s FW Rev. %c.%c (ID=%x) ",
43515196Sdg	    aha->model, aha->fw_major, aha->fw_minor, aha->boardid);
43615196Sdg
43715196Sdg	if (aha->diff_bus != 0)
43815196Sdg		printf("Diff ");
43915196Sdg
44015196Sdg	printf("SCSI Host Adapter, SCSI ID %d, %d CCBs\n", aha->scsi_id,
44189935Syar	    aha->max_ccbs);
44289935Syar
44356668Sshin	/*
44415196Sdg	 * Create our DMA tags.  These tags define the kinds of device
44515196Sdg	 * accessible memory allocations and memory mappings we will
44615196Sdg	 * need to perform during normal operation.
44715196Sdg	 *
448120059Sume	 * Unless we need to further restrict the allocation, we rely
449120059Sume	 * on the restrictions of the parent dmat, hence the common
45015196Sdg	 * use of MAXADDR and MAXSIZE.
451120059Sume	 */
452120059Sume
453120059Sume	/* DMA tag for mapping buffers into device visible space. */
454120059Sume	if (bus_dma_tag_create( /* parent	*/ aha->parent_dmat,
455120059Sume				/* alignment	*/ 1,
456120059Sume				/* boundary	*/ 0,
457120059Sume				/* lowaddr	*/ BUS_SPACE_MAXADDR,
458120059Sume				/* highaddr	*/ BUS_SPACE_MAXADDR,
459120059Sume				/* filter	*/ NULL,
460120059Sume				/* filterarg	*/ NULL,
46115196Sdg				/* maxsize	*/ MAXBSIZE,
462120059Sume				/* nsegments	*/ AHA_NSEG,
46315196Sdg				/* maxsegsz	*/ BUS_SPACE_MAXSIZE_24BIT,
46417483Sjulian				/* flags	*/ BUS_DMA_ALLOCNOW,
46517483Sjulian				/* lockfunc	*/ busdma_lock_mutex,
46617483Sjulian				/* lockarg	*/ &Giant,
46799213Smaxim				&aha->buffer_dmat) != 0) {
46817483Sjulian		goto error_exit;
46917483Sjulian	}
47017483Sjulian
47117483Sjulian	aha->init_level++;
47217483Sjulian	/* DMA tag for our mailboxes */
47346078Simp	if (bus_dma_tag_create(	/* parent	*/ aha->parent_dmat,
47417483Sjulian				/* alignment	*/ 1,
47517483Sjulian				/* boundary	*/ 0,
47617483Sjulian				/* lowaddr	*/ BUS_SPACE_MAXADDR,
47717483Sjulian				/* highaddr	*/ BUS_SPACE_MAXADDR,
47846078Simp				/* filter	*/ NULL,
47917483Sjulian				/* filterarg	*/ NULL,
48017483Sjulian				/* maxsize	*/ aha->num_boxes *
48117483Sjulian						   (sizeof(aha_mbox_in_t) +
48217483Sjulian						    sizeof(aha_mbox_out_t)),
48317483Sjulian				/* nsegments	*/ 1,
48417483Sjulian				/* maxsegsz	*/ BUS_SPACE_MAXSIZE_24BIT,
48517483Sjulian				/* flags	*/ 0,
48615196Sdg				/* lockfunc	*/ busdma_lock_mutex,
48715196Sdg				/* lockarg	*/ &Giant,
48815196Sdg				&aha->mailbox_dmat) != 0) {
48915196Sdg		goto error_exit;
490120059Sume        }
491120059Sume
492120059Sume	aha->init_level++;
493120059Sume
494120059Sume	/* Allocation for our mailboxes */
495120059Sume	if (bus_dmamem_alloc(aha->mailbox_dmat, (void **)&aha->out_boxes,
496120059Sume	    BUS_DMA_NOWAIT, &aha->mailbox_dmamap) != 0)
497120059Sume		goto error_exit;
498120059Sume
499120059Sume	aha->init_level++;
500120059Sume
501120059Sume	/* And permanently map them */
502120059Sume	bus_dmamap_load(aha->mailbox_dmat, aha->mailbox_dmamap,
503120059Sume	    aha->out_boxes, aha->num_boxes * (sizeof(aha_mbox_in_t) +
504120059Sume	    sizeof(aha_mbox_out_t)), ahamapmboxes, aha, /*flags*/0);
505120059Sume
506120059Sume	aha->init_level++;
507120059Sume
508120059Sume	aha->in_boxes = (aha_mbox_in_t *)&aha->out_boxes[aha->num_boxes];
509120059Sume
510120059Sume	ahainitmboxes(aha);
511120059Sume
512120059Sume	/* DMA tag for our ccb structures */
513120059Sume	if (bus_dma_tag_create(	/* parent	*/ aha->parent_dmat,
51415196Sdg				/* alignment	*/ 1,
51515196Sdg				/* boundary	*/ 0,
51615196Sdg				/* lowaddr	*/ BUS_SPACE_MAXADDR,
51715196Sdg				/* highaddr	*/ BUS_SPACE_MAXADDR,
51815196Sdg				/* filter	*/ NULL,
51915196Sdg				/* filterarg	*/ NULL,
52015196Sdg				/* maxsize	*/ aha->max_ccbs *
52115196Sdg						   sizeof(struct aha_ccb),
52215196Sdg				/* nsegments	*/ 1,
52315196Sdg				/* maxsegsz	*/ BUS_SPACE_MAXSIZE_24BIT,
52489935Syar				/* flags	*/ 0,
52589935Syar				/* lockfunc	*/ busdma_lock_mutex,
5261592Srgrimes				/* lockarg	*/ &Giant,
52789935Syar				&aha->ccb_dmat) != 0) {
52889935Syar		goto error_exit;
52989935Syar        }
53089935Syar
53189935Syar	aha->init_level++;
53289935Syar
53389935Syar	/* Allocation for our ccbs */
53489935Syar	if (bus_dmamem_alloc(aha->ccb_dmat, (void **)&aha->aha_ccb_array,
53589935Syar	    BUS_DMA_NOWAIT, &aha->ccb_dmamap) != 0)
53689935Syar		goto error_exit;
53789935Syar
53889935Syar	aha->init_level++;
53989935Syar
54089935Syar	/* And permanently map them */
54189935Syar	bus_dmamap_load(aha->ccb_dmat, aha->ccb_dmamap, aha->aha_ccb_array,
54215196Sdg	    aha->max_ccbs * sizeof(struct aha_ccb), ahamapccbs, aha, /*flags*/0);
54315196Sdg
54415196Sdg	aha->init_level++;
54515196Sdg
54615196Sdg	/* DMA tag for our S/G structures.  We allocate in page sized chunks */
547109742Syar	if (bus_dma_tag_create(	/* parent	*/ aha->parent_dmat,
54825283Sdavidn				/* alignment	*/ 1,
54925283Sdavidn				/* boundary	*/ 0,
55056668Sshin				/* lowaddr	*/ BUS_SPACE_MAXADDR,
55125283Sdavidn				/* highaddr	*/ BUS_SPACE_MAXADDR,
55215196Sdg				/* filter	*/ NULL,
55356668Sshin				/* filterarg	*/ NULL,
55456668Sshin				/* maxsize	*/ PAGE_SIZE,
55515196Sdg				/* nsegments	*/ 1,
556100612Syar				/* maxsegsz	*/ BUS_SPACE_MAXSIZE_24BIT,
557100609Syar				/* flags	*/ 0,
55856668Sshin				/* lockfunc	*/ busdma_lock_mutex,
55915196Sdg				/* lockarg	*/ &Giant,
56035482Sdg				&aha->sg_dmat) != 0)
56135482Sdg		goto error_exit;
56235482Sdg
56335482Sdg	aha->init_level++;
56435482Sdg
565100609Syar	/* Perform initial CCB allocation */
56635482Sdg	bzero(aha->aha_ccb_array, aha->max_ccbs * sizeof(struct aha_ccb));
56756668Sshin	ahaallocccbs(aha);
56815196Sdg
56917435Spst	if (aha->num_ccbs == 0) {
57031973Simp		device_printf(aha->dev,
57117435Spst		    "aha_init - Unable to allocate initial ccbs\n");
5721592Srgrimes		goto error_exit;
5731592Srgrimes	}
574100612Syar
575100609Syar	/*
5761592Srgrimes	 * Note that we are going and return (to probe)
5771592Srgrimes	 */
5781592Srgrimes	return (0);
5791592Srgrimes
5801592Srgrimeserror_exit:
5811592Srgrimes
58256668Sshin	return (ENXIO);
5831592Srgrimes}
5841592Srgrimes
5851592Srgrimesint
5861592Srgrimesaha_attach(struct aha_softc *aha)
5871592Srgrimes{
5881592Srgrimes	int tagged_dev_openings;
5891592Srgrimes	struct cam_devq *devq;
5901592Srgrimes
5911592Srgrimes	/*
5921592Srgrimes	 * We don't do tagged queueing, since the aha cards don't
5931592Srgrimes	 * support it.
5941592Srgrimes	 */
5951592Srgrimes	tagged_dev_openings = 0;
5961592Srgrimes
5971592Srgrimes	/*
5981592Srgrimes	 * Create the device queue for our SIM.
5991592Srgrimes	 */
6001592Srgrimes	devq = cam_simq_alloc(aha->max_ccbs - 1);
6011592Srgrimes	if (devq == NULL)
6021592Srgrimes		return (ENOMEM);
6031592Srgrimes
6041592Srgrimes	/*
60525283Sdavidn	 * Construct our SIM entry
60625283Sdavidn	 */
60725283Sdavidn	aha->sim = cam_sim_alloc(ahaaction, ahapoll, "aha", aha, aha->unit, 2,
6081592Srgrimes	    tagged_dev_openings, devq);
60925283Sdavidn	if (aha->sim == NULL) {
6101592Srgrimes		cam_simq_free(devq);
6111592Srgrimes		return (ENOMEM);
6121592Srgrimes	}
6131592Srgrimes	if (xpt_bus_register(aha->sim, 0) != CAM_SUCCESS) {
6141592Srgrimes		cam_sim_free(aha->sim, /*free_devq*/TRUE);
6151592Srgrimes		return (ENXIO);
6161592Srgrimes	}
6171592Srgrimes	if (xpt_create_path(&aha->path, /*periph*/NULL, cam_sim_path(aha->sim),
6181592Srgrimes	    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
61925283Sdavidn		xpt_bus_deregister(cam_sim_path(aha->sim));
62027650Sdavidn		cam_sim_free(aha->sim, /*free_devq*/TRUE);
62176096Smarkm		return (ENXIO);
62245422Sbrian	}
62345422Sbrian
62425283Sdavidn	return (0);
625110037Syar}
626110037Syar
627110037Syarstatic void
628110037Syarahaallocccbs(struct aha_softc *aha)
6291592Srgrimes{
6301592Srgrimes	struct aha_ccb *next_ccb;
6311592Srgrimes	struct sg_map_node *sg_map;
6321592Srgrimes	bus_addr_t physaddr;
6331592Srgrimes	aha_sg_t *segs;
6341592Srgrimes	int newcount;
63590148Simp	int i;
6361592Srgrimes
6371592Srgrimes	next_ccb = &aha->aha_ccb_array[aha->num_ccbs];
63876096Smarkm
6391592Srgrimes	sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT);
64031329Scharnier
6411592Srgrimes	if (sg_map == NULL)
6421592Srgrimes		return;
64389935Syar
64490148Simp	/* Allocate S/G space for the next batch of CCBS */
64589935Syar	if (bus_dmamem_alloc(aha->sg_dmat, (void **)&sg_map->sg_vaddr,
64689935Syar	    BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) {
64789935Syar		free(sg_map, M_DEVBUF);
64889935Syar		return;
64989935Syar	}
65089935Syar
65125283Sdavidn	SLIST_INSERT_HEAD(&aha->sg_maps, sg_map, links);
6521592Srgrimes
65325283Sdavidn	bus_dmamap_load(aha->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr,
65425283Sdavidn	    PAGE_SIZE, ahamapsgs, aha, /*flags*/0);
65525283Sdavidn
65625283Sdavidn	segs = sg_map->sg_vaddr;
65790148Simp	physaddr = sg_map->sg_physaddr;
65825283Sdavidn
659100182Syar	newcount = (PAGE_SIZE / (AHA_NSEG * sizeof(aha_sg_t)));
66099877Syar	for (i = 0; aha->num_ccbs < aha->max_ccbs && i < newcount; i++) {
66125283Sdavidn		int error;
66299877Syar
66399877Syar		next_ccb->sg_list = segs;
664100182Syar		next_ccb->sg_list_phys = physaddr;
66525283Sdavidn		next_ccb->flags = ACCB_FREE;
66656668Sshin		error = bus_dmamap_create(aha->buffer_dmat, /*flags*/0,
66725283Sdavidn		    &next_ccb->dmamap);
66825283Sdavidn		if (error != 0)
66925283Sdavidn			break;
67025283Sdavidn		SLIST_INSERT_HEAD(&aha->free_aha_ccbs, next_ccb, links);
67199877Syar		segs += AHA_NSEG;
67276096Smarkm		physaddr += (AHA_NSEG * sizeof(aha_sg_t));
67399877Syar		next_ccb++;
67499877Syar		aha->num_ccbs++;
67599877Syar	}
67699877Syar
67799877Syar	/* Reserve a CCB for error recovery */
67899877Syar	if (aha->recovery_accb == NULL) {
67957124Sshin		aha->recovery_accb = SLIST_FIRST(&aha->free_aha_ccbs);
68056668Sshin		SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links);
68156668Sshin	}
68256668Sshin}
68356668Sshin
684102183Syarstatic __inline void
68557124Sshinahafreeccb(struct aha_softc *aha, struct aha_ccb *accb)
68625283Sdavidn{
68725283Sdavidn	int s;
68825283Sdavidn
68925283Sdavidn	s = splcam();
69025283Sdavidn	if ((accb->flags & ACCB_ACTIVE) != 0)
69125283Sdavidn		LIST_REMOVE(&accb->ccb->ccb_h, sim_links.le);
69225283Sdavidn	if (aha->resource_shortage != 0
693102474Syar	    && (accb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) {
69456668Sshin		accb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
69556668Sshin		aha->resource_shortage = FALSE;
69656668Sshin	}
69799877Syar	accb->flags = ACCB_FREE;
69856668Sshin	SLIST_INSERT_HEAD(&aha->free_aha_ccbs, accb, links);
69925283Sdavidn	aha->active_ccbs--;
70099877Syar	splx(s);
70199877Syar}
70225283Sdavidn
70399877Syarstatic struct aha_ccb*
70499877Syarahagetccb(struct aha_softc *aha)
70599877Syar{
70699877Syar	struct	aha_ccb* accb;
70799877Syar	int	s;
70899877Syar
70999877Syar	s = splcam();
71099877Syar	if ((accb = SLIST_FIRST(&aha->free_aha_ccbs)) != NULL) {
71199877Syar		SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links);
71225283Sdavidn		aha->active_ccbs++;
71325283Sdavidn	} else if (aha->num_ccbs < aha->max_ccbs) {
71499877Syar		ahaallocccbs(aha);
71599877Syar		accb = SLIST_FIRST(&aha->free_aha_ccbs);
71699877Syar		if (accb == NULL)
717100182Syar			device_printf(aha->dev, "Can't malloc ACCB\n");
71856668Sshin		else {
719100182Syar			SLIST_REMOVE_HEAD(&aha->free_aha_ccbs, links);
720100182Syar			aha->active_ccbs++;
721100182Syar		}
722100182Syar	}
723100182Syar	splx(s);
724100182Syar
725100182Syar	return (accb);
726100182Syar}
727100182Syar
728100182Syarstatic void
729100182Syarahaaction(struct cam_sim *sim, union ccb *ccb)
730100182Syar{
731100182Syar	struct	aha_softc *aha;
732100182Syar	int s;
733100182Syar
734100182Syar	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahaaction\n"));
735100182Syar
736100182Syar	aha = (struct aha_softc *)cam_sim_softc(sim);
737100182Syar
738100182Syar	switch (ccb->ccb_h.func_code) {
739100182Syar	/* Common cases first */
740100182Syar	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
741100182Syar	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */	{
742100182Syar		struct	aha_ccb	*accb;
743100182Syar		struct	aha_hccb *hccb;
744100182Syar
745100182Syar		/*
746100182Syar		 * Get an accb to use.
747100182Syar		 */
748100182Syar		if ((accb = ahagetccb(aha)) == NULL) {
749100182Syar			s = splcam();
750100182Syar			aha->resource_shortage = TRUE;
751100182Syar			splx(s);
752100182Syar			xpt_freeze_simq(aha->sim, /*count*/1);
75356668Sshin			ccb->ccb_h.status = CAM_REQUEUE_REQ;
75456668Sshin			xpt_done(ccb);
75556668Sshin			return;
756102183Syar		}
75799877Syar		hccb = &accb->hccb;
75856668Sshin
75962100Sdavidn		/*
76056668Sshin		 * So we can find the ACCB when an abort is requested
76162100Sdavidn		 */
76225283Sdavidn		accb->ccb = ccb;
76357124Sshin		ccb->ccb_h.ccb_accb_ptr = accb;
76457124Sshin		ccb->ccb_h.ccb_aha_ptr = aha;
76557124Sshin
76657124Sshin		/*
76757124Sshin		 * Put all the arguments for the xfer in the accb
76857124Sshin		 */
76957124Sshin		hccb->target = ccb->ccb_h.target_id;
77062100Sdavidn		hccb->lun = ccb->ccb_h.target_lun;
77162100Sdavidn		hccb->ahastat = 0;
77257124Sshin		hccb->sdstat = 0;
773100183Syar
77462100Sdavidn		if (ccb->ccb_h.func_code == XPT_SCSI_IO) {
77562100Sdavidn			struct ccb_scsiio *csio;
77625283Sdavidn			struct ccb_hdr *ccbh;
77725283Sdavidn
77825283Sdavidn			csio = &ccb->csio;
77999877Syar			ccbh = &csio->ccb_h;
780102183Syar			hccb->opcode = aha->ccb_ccb_opcode;
781100182Syar			hccb->datain = (ccb->ccb_h.flags & CAM_DIR_IN) != 0;
782102473Syar			hccb->dataout = (ccb->ccb_h.flags & CAM_DIR_OUT) != 0;
783106754Syar			hccb->cmd_len = csio->cdb_len;
784102473Syar			if (hccb->cmd_len > sizeof(hccb->scsi_cdb)) {
785100182Syar				ccb->ccb_h.status = CAM_REQ_INVALID;
786102473Syar				ahafreeccb(aha, accb);
78757124Sshin				xpt_done(ccb);
78857124Sshin				return;
78925283Sdavidn			}
79025283Sdavidn			hccb->sense_len = csio->sense_len;
79156668Sshin			if ((ccbh->flags & CAM_CDB_POINTER) != 0) {
79225283Sdavidn				if ((ccbh->flags & CAM_CDB_PHYS) == 0) {
79325283Sdavidn					bcopy(csio->cdb_io.cdb_ptr,
79456668Sshin					      hccb->scsi_cdb, hccb->cmd_len);
79557124Sshin				} else {
79656668Sshin					/* I guess I could map it in... */
797100259Syar					ccbh->status = CAM_REQ_INVALID;
798100259Syar					ahafreeccb(aha, accb);
79956668Sshin					xpt_done(ccb);
80056668Sshin					return;
801100259Syar				}
802100259Syar			} else {
80356668Sshin				bcopy(csio->cdb_io.cdb_bytes,
80456668Sshin				      hccb->scsi_cdb, hccb->cmd_len);
80556668Sshin			}
806102473Syar			/*
807102473Syar			 * If we have any data to send with this command,
808102473Syar			 * map it into bus space.
809102473Syar			 */
810102473Syar		        /* Only use S/G if there is a transfer */
81199877Syar			if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
81256668Sshin				if ((ccbh->flags & CAM_SCATTER_VALID) == 0) {
81356668Sshin					/*
814100612Syar					 * We've been given a pointer
81557124Sshin					 * to a single buffer.
81656668Sshin					 */
817100182Syar					if ((ccbh->flags & CAM_DATA_PHYS)==0) {
81825283Sdavidn						int error;
819100182Syar
82025283Sdavidn						s = splsoftvm();
82125283Sdavidn						error = bus_dmamap_load(
82225283Sdavidn						    aha->buffer_dmat,
823100182Syar						    accb->dmamap,
82425283Sdavidn						    csio->data_ptr,
82525283Sdavidn						    csio->dxfer_len,
826100182Syar						    ahaexecuteccb,
82725283Sdavidn						    accb,
82825283Sdavidn						    /*flags*/0);
82925283Sdavidn						if (error == EINPROGRESS) {
830102183Syar							/*
831102183Syar							 * So as to maintain
832102183Syar							 * ordering, freeze the
833102183Syar							 * controller queue
834102183Syar							 * until our mapping is
835102183Syar							 * returned.
836102473Syar							 */
837102473Syar							xpt_freeze_simq(aha->sim,
838102473Syar									1);
839102473Syar							csio->ccb_h.status |=
840102473Syar							    CAM_RELEASE_SIMQ;
841100182Syar						}
842102473Syar						splx(s);
843100182Syar					} else {
844100182Syar						struct bus_dma_segment seg;
845100182Syar
846100182Syar						/* Pointer to physical buffer */
847100182Syar						seg.ds_addr =
848100182Syar						    (bus_addr_t)csio->data_ptr;
849100182Syar						seg.ds_len = csio->dxfer_len;
850100182Syar						ahaexecuteccb(accb, &seg, 1, 0);
851100182Syar					}
852100263Syar				} else {
853100263Syar					struct bus_dma_segment *segs;
85456668Sshin
85599877Syar					if ((ccbh->flags & CAM_DATA_PHYS) != 0)
85699877Syar						panic("ahaaction - Physical "
85799877Syar						      "segment pointers "
85825283Sdavidn						      "unsupported");
85925283Sdavidn
86025283Sdavidn					if ((ccbh->flags&CAM_SG_LIST_PHYS)==0)
86125283Sdavidn						panic("ahaaction - Virtual "
86225283Sdavidn						      "segment addresses "
86325283Sdavidn						      "unsupported");
86490148Simp
86525283Sdavidn					/* Just use the segments provided */
86625283Sdavidn					segs = (struct bus_dma_segment *)
86756668Sshin					    csio->data_ptr;
86856668Sshin					ahaexecuteccb(accb, segs,
86956668Sshin						     csio->sglist_cnt, 0);
87056668Sshin				}
87157124Sshin			} else {
87225283Sdavidn				ahaexecuteccb(accb, NULL, 0, 0);
87356668Sshin			}
87456668Sshin		} else {
87556668Sshin			hccb->opcode = INITIATOR_BUS_DEV_RESET;
87656668Sshin			/* No data transfer */
87756668Sshin			hccb->datain = TRUE;
87856668Sshin			hccb->dataout = TRUE;
87956668Sshin			hccb->cmd_len = 0;
88056668Sshin			hccb->sense_len = 0;
88156668Sshin			ahaexecuteccb(accb, NULL, 0, 0);
88256668Sshin		}
88325283Sdavidn		break;
88456668Sshin	}
88556668Sshin	case XPT_EN_LUN:		/* Enable LUN as a target */
88625283Sdavidn	case XPT_TARGET_IO:		/* Execute target I/O request */
88762100Sdavidn	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
88857124Sshin	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/
88925283Sdavidn	case XPT_ABORT:			/* Abort the specified CCB */
89025283Sdavidn		/* XXX Implement */
89125283Sdavidn		ccb->ccb_h.status = CAM_REQ_INVALID;
89256668Sshin		xpt_done(ccb);
89356668Sshin		break;
89457124Sshin	case XPT_SET_TRAN_SETTINGS:
89556668Sshin		/* XXX Implement */
89657124Sshin		ccb->ccb_h.status = CAM_PROVIDE_FAIL;
89756668Sshin		xpt_done(ccb);
89856668Sshin		break;
89956668Sshin	case XPT_GET_TRAN_SETTINGS:
90056668Sshin	/* Get default/user set transfer settings for the target */
90156668Sshin	{
90262100Sdavidn		struct	ccb_trans_settings *cts = &ccb->cts;
90362100Sdavidn		u_int	target_mask = 0x01 << ccb->ccb_h.target_id;
90425283Sdavidn#ifdef	CAM_NEW_TRAN_CODE
90556668Sshin		struct ccb_trans_settings_scsi *scsi =
90625283Sdavidn		    &cts->proto_specific.scsi;
90725283Sdavidn		struct ccb_trans_settings_spi *spi =
90825283Sdavidn		    &cts->xport_specific.spi;
90925283Sdavidn
91025283Sdavidn		cts->protocol = PROTO_SCSI;
91125283Sdavidn		cts->protocol_version = SCSI_REV_2;
91225283Sdavidn		cts->transport = XPORT_SPI;
9131592Srgrimes		cts->transport_version = 2;
9141592Srgrimes		if (cts->type == CTS_TYPE_USER_SETTINGS) {
9151592Srgrimes			spi->flags = 0;
91690148Simp			if ((aha->disc_permitted & target_mask) != 0)
9171592Srgrimes				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
9181592Srgrimes			spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
9191592Srgrimes			if ((aha->sync_permitted & target_mask) != 0) {
9201592Srgrimes				if (aha->boardid >= BOARD_1542CF)
9211592Srgrimes					spi->sync_period = 25;
9221592Srgrimes				else
9231592Srgrimes					spi->sync_period = 50;
9241592Srgrimes			} else {
9251592Srgrimes				spi->sync_period = 0;
9261592Srgrimes			}
9271592Srgrimes
9281592Srgrimes			if (spi->sync_period != 0)
9291592Srgrimes				spi->sync_offset = 15;
9301592Srgrimes
9311592Srgrimes			spi->valid = CTS_SPI_VALID_SYNC_RATE
9321592Srgrimes				   | CTS_SPI_VALID_SYNC_OFFSET
9331592Srgrimes				   | CTS_SPI_VALID_BUS_WIDTH
9341592Srgrimes				   | CTS_SPI_VALID_DISC;
93590148Simp			scsi->valid = CTS_SCSI_VALID_TQ;
9361592Srgrimes		} else {
9371592Srgrimes			ahafetchtransinfo(aha, cts);
9381592Srgrimes		}
9391592Srgrimes#else
9401592Srgrimes		if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) {
9411592Srgrimes			cts->flags = 0;
9421592Srgrimes			if ((aha->disc_permitted & target_mask) != 0)
9431592Srgrimes				cts->flags |= CCB_TRANS_DISC_ENB;
9441592Srgrimes			cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
9451592Srgrimes			if ((aha->sync_permitted & target_mask) != 0) {
9461592Srgrimes				if (aha->boardid >= BOARD_1542CF)
9471592Srgrimes					cts->sync_period = 25;
9481592Srgrimes				else
9491592Srgrimes					cts->sync_period = 50;
9501592Srgrimes			} else
9511592Srgrimes				cts->sync_period = 0;
9521592Srgrimes
9531592Srgrimes			if (cts->sync_period != 0)
9541592Srgrimes				cts->sync_offset = 15;
9551592Srgrimes
9561592Srgrimes			cts->valid = CCB_TRANS_SYNC_RATE_VALID
9571592Srgrimes				   | CCB_TRANS_SYNC_OFFSET_VALID
9581592Srgrimes				   | CCB_TRANS_BUS_WIDTH_VALID
9591592Srgrimes				   | CCB_TRANS_DISC_VALID
96064778Ssheldonh				   | CCB_TRANS_TQ_VALID;
9611592Srgrimes		} else {
9621592Srgrimes			ahafetchtransinfo(aha, cts);
9631592Srgrimes		}
9641592Srgrimes#endif
9651592Srgrimes
9661592Srgrimes		ccb->ccb_h.status = CAM_REQ_CMP;
9671592Srgrimes		xpt_done(ccb);
9681592Srgrimes		break;
9691592Srgrimes	}
9701592Srgrimes	case XPT_CALC_GEOMETRY:
9711592Srgrimes	{
9721592Srgrimes		struct	  ccb_calc_geometry *ccg;
9731592Srgrimes		uint32_t size_mb;
97490148Simp		uint32_t secs_per_cylinder;
9751592Srgrimes
9761592Srgrimes		ccg = &ccb->ccg;
9771592Srgrimes		size_mb = ccg->volume_size
9781592Srgrimes			/ ((1024L * 1024L) / ccg->block_size);
9791592Srgrimes		if (size_mb >= 1024 && (aha->extended_trans != 0)) {
9801592Srgrimes			if (size_mb >= 2048) {
9811592Srgrimes				ccg->heads = 255;
98217435Spst				ccg->secs_per_track = 63;
98317435Spst			} else {
98417435Spst				ccg->heads = 128;
9851592Srgrimes				ccg->secs_per_track = 32;
9861592Srgrimes			}
9871592Srgrimes		} else {
9881592Srgrimes			ccg->heads = 64;
9891592Srgrimes			ccg->secs_per_track = 32;
9901592Srgrimes		}
991109893Syar		secs_per_cylinder = ccg->heads * ccg->secs_per_track;
992109893Syar		ccg->cylinders = ccg->volume_size / secs_per_cylinder;
9931592Srgrimes		ccb->ccb_h.status = CAM_REQ_CMP;
99425283Sdavidn		xpt_done(ccb);
99525283Sdavidn		break;
99625283Sdavidn	}
9971592Srgrimes	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
99825283Sdavidn		ahareset(aha, /*hardreset*/TRUE);
9991592Srgrimes		ccb->ccb_h.status = CAM_REQ_CMP;
10001592Srgrimes		xpt_done(ccb);
10011592Srgrimes		break;
10023938Spst	case XPT_TERM_IO:		/* Terminate the I/O process */
10031592Srgrimes		/* XXX Implement */
10041592Srgrimes		ccb->ccb_h.status = CAM_REQ_INVALID;
10051592Srgrimes		xpt_done(ccb);
10061592Srgrimes		break;
10071592Srgrimes	case XPT_PATH_INQ:		/* Path routing inquiry */
10081592Srgrimes	{
10091592Srgrimes		struct ccb_pathinq *cpi = &ccb->cpi;
101020042Storstenb
101120042Storstenb		cpi->version_num = 1; /* XXX??? */
101220042Storstenb		cpi->hba_inquiry = PI_SDTR_ABLE;
101320042Storstenb		cpi->target_sprt = 0;
101420042Storstenb		cpi->hba_misc = 0;
101517478Smarkm		cpi->hba_eng_cnt = 0;
10161592Srgrimes		cpi->max_target = 7;
10171592Srgrimes		cpi->max_lun = 7;
1018124687Scharnier		cpi->initiator_id = aha->scsi_id;
10191592Srgrimes		cpi->bus_id = cam_sim_bus(sim);
10201592Srgrimes		cpi->base_transfer_speed = 3300;
10211592Srgrimes		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
10221592Srgrimes		strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN);
10231592Srgrimes		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
1024109893Syar		cpi->unit_number = cam_sim_unit(sim);
10251592Srgrimes#ifdef	CAM_NEW_TRAN_CODE
10261592Srgrimes                cpi->transport = XPORT_SPI;
10271592Srgrimes                cpi->transport_version = 2;
10281592Srgrimes                cpi->protocol = PROTO_SCSI;
10291592Srgrimes                cpi->protocol_version = SCSI_REV_2;
10301592Srgrimes#endif
10311592Srgrimes		cpi->ccb_h.status = CAM_REQ_CMP;
10321592Srgrimes		xpt_done(ccb);
10331592Srgrimes		break;
10341592Srgrimes	}
10351592Srgrimes	default:
103688763Sache		ccb->ccb_h.status = CAM_REQ_INVALID;
103788763Sache		xpt_done(ccb);
103879469Smarkm		break;
103979469Smarkm	}
104088763Sache}
104188763Sache
104288763Sachestatic void
104388763Sacheahaexecuteccb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
104488763Sache{
104588763Sache	struct	 aha_ccb *accb;
104688763Sache	union	 ccb *ccb;
104788763Sache	struct	 aha_softc *aha;
104888763Sache	int	 s;
104984146Sache	uint32_t paddr;
105088763Sache
10511592Srgrimes	accb = (struct aha_ccb *)arg;
10521592Srgrimes	ccb = accb->ccb;
10531592Srgrimes	aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr;
10541592Srgrimes
10551592Srgrimes	if (error != 0) {
10561592Srgrimes		if (error != EFBIG)
10571592Srgrimes			device_printf(aha->dev,
10581592Srgrimes			    "Unexepected error 0x%x returned from "
10591592Srgrimes			    "bus_dmamap_load\n", error);
10601592Srgrimes		if (ccb->ccb_h.status == CAM_REQ_INPROG) {
1061109893Syar			xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
1062109893Syar			ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN;
1063109893Syar		}
10641592Srgrimes		ahafreeccb(aha, accb);
10651592Srgrimes		xpt_done(ccb);
1066109893Syar		return;
10671592Srgrimes	}
10681592Srgrimes
10691592Srgrimes	if (nseg != 0) {
107099877Syar		aha_sg_t *sg;
107199877Syar		bus_dma_segment_t *end_seg;
10721592Srgrimes		bus_dmasync_op_t op;
107317435Spst
107499877Syar		end_seg = dm_segs + nseg;
107599877Syar
107699877Syar		/* Copy the segments into our SG list */
107799877Syar		sg = accb->sg_list;
107899877Syar		while (dm_segs < end_seg) {
107999877Syar			ahautoa24(dm_segs->ds_len, sg->len);
108099877Syar			ahautoa24(dm_segs->ds_addr, sg->addr);
108199877Syar			sg++;
108299877Syar			dm_segs++;
108399877Syar		}
108499877Syar
108599877Syar		if (nseg > 1) {
108699877Syar			accb->hccb.opcode = aha->ccb_sg_opcode;
108799877Syar			ahautoa24((sizeof(aha_sg_t) * nseg),
108899877Syar			    accb->hccb.data_len);
108999877Syar			ahautoa24(accb->sg_list_phys, accb->hccb.data_addr);
109099877Syar		} else {
109199877Syar			bcopy(accb->sg_list->len, accb->hccb.data_len, 3);
109299877Syar			bcopy(accb->sg_list->addr, accb->hccb.data_addr, 3);
109399877Syar		}
109499877Syar
109599877Syar		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
109699877Syar			op = BUS_DMASYNC_PREREAD;
109799877Syar		else
109899877Syar			op = BUS_DMASYNC_PREWRITE;
109999877Syar
1100109893Syar		bus_dmamap_sync(aha->buffer_dmat, accb->dmamap, op);
110199877Syar
1102109893Syar	} else {
1103109893Syar		accb->hccb.opcode = INITIATOR_CCB;
1104109893Syar		ahautoa24(0, accb->hccb.data_len);
1105109893Syar		ahautoa24(0, accb->hccb.data_addr);
1106109893Syar	}
1107109893Syar
1108109893Syar	s = splcam();
1109109893Syar
1110109893Syar	/*
1111109893Syar	 * Last time we need to check if this CCB needs to
1112109893Syar	 * be aborted.
1113109893Syar	 */
1114109893Syar	if (ccb->ccb_h.status != CAM_REQ_INPROG) {
1115109893Syar		if (nseg != 0)
1116109893Syar			bus_dmamap_unload(aha->buffer_dmat, accb->dmamap);
1117109893Syar		ahafreeccb(aha, accb);
11181592Srgrimes		xpt_done(ccb);
111999877Syar		splx(s);
112099877Syar		return;
112199877Syar	}
112299877Syar
112399877Syar	accb->flags = ACCB_ACTIVE;
1124109893Syar	ccb->ccb_h.status |= CAM_SIM_QUEUED;
1125109893Syar	LIST_INSERT_HEAD(&aha->pending_ccbs, &ccb->ccb_h, sim_links.le);
1126109893Syar
1127109893Syar	ccb->ccb_h.timeout_ch = timeout(ahatimeout, (caddr_t)accb,
1128109938Syar	    (ccb->ccb_h.timeout * hz) / 1000);
1129109938Syar
1130109938Syar	/* Tell the adapter about this command */
1131109893Syar	if (aha->cur_outbox->action_code != AMBO_FREE) {
1132109893Syar		/*
1133109893Syar		 * We should never encounter a busy mailbox.
1134109893Syar		 * If we do, warn the user, and treat it as
1135109893Syar		 * a resource shortage.  If the controller is
113699877Syar		 * hung, one of the pending transactions will
113799877Syar		 * timeout causing us to start recovery operations.
113899877Syar		 */
113999877Syar		device_printf(aha->dev,
11401592Srgrimes		    "Encountered busy mailbox with %d out of %d "
11411592Srgrimes		    "commands active!!!", aha->active_ccbs, aha->max_ccbs);
11421592Srgrimes		untimeout(ahatimeout, accb, ccb->ccb_h.timeout_ch);
11431592Srgrimes		if (nseg != 0)
11441592Srgrimes			bus_dmamap_unload(aha->buffer_dmat, accb->dmamap);
11451592Srgrimes		ahafreeccb(aha, accb);
11461592Srgrimes		aha->resource_shortage = TRUE;
11471592Srgrimes		xpt_freeze_simq(aha->sim, /*count*/1);
11481592Srgrimes		ccb->ccb_h.status = CAM_REQUEUE_REQ;
11491592Srgrimes		xpt_done(ccb);
115090148Simp		return;
11511592Srgrimes	}
115274874Smarkm	paddr = ahaccbvtop(aha, accb);
115374874Smarkm	ahautoa24(paddr, aha->cur_outbox->ccb_addr);
115474874Smarkm	aha->cur_outbox->action_code = AMBO_START;
11551592Srgrimes	aha_outb(aha, COMMAND_REG, AOP_START_MBOX);
11561592Srgrimes
1157102311Syar	ahanextoutbox(aha);
115889920Sume	splx(s);
11591592Srgrimes}
116025101Sdavidn
116125101Sdavidnvoid
1162105877Srwatsonaha_intr(void *arg)
1163105877Srwatson{
116425101Sdavidn	struct	aha_softc *aha;
116574874Smarkm	u_int	intstat;
116674874Smarkm	uint32_t paddr;
116774874Smarkm
116874874Smarkm	aha = (struct aha_softc *)arg;
116974874Smarkm	while (((intstat = aha_inb(aha, INTSTAT_REG)) & INTR_PENDING) != 0) {
117074874Smarkm		if ((intstat & CMD_COMPLETE) != 0) {
117174874Smarkm			aha->latched_status = aha_inb(aha, STATUS_REG);
117274874Smarkm			aha->command_cmp = TRUE;
117374874Smarkm		}
11741592Srgrimes
11751592Srgrimes		aha_outb(aha, CONTROL_REG, RESET_INTR);
117617435Spst
11771592Srgrimes		if ((intstat & IMB_LOADED) != 0) {
11781592Srgrimes			while (aha->cur_inbox->comp_code != AMBI_FREE) {
117974874Smarkm				paddr = aha_a24tou(aha->cur_inbox->ccb_addr);
118051433Smarkm				ahadone(aha, ahaccbptov(aha, paddr),
118151433Smarkm				    aha->cur_inbox->comp_code);
118251433Smarkm				aha->cur_inbox->comp_code = AMBI_FREE;
118351433Smarkm				ahanextinbox(aha);
118451433Smarkm			}
118551433Smarkm		}
118651433Smarkm
118751433Smarkm		if ((intstat & SCSI_BUS_RESET) != 0) {
118851433Smarkm			ahareset(aha, /*hardreset*/FALSE);
118951433Smarkm		}
119051433Smarkm	}
119151433Smarkm}
119251433Smarkm
119351433Smarkmstatic void
119451433Smarkmahadone(struct aha_softc *aha, struct aha_ccb *accb, aha_mbi_comp_code_t comp_code)
119551433Smarkm{
119651433Smarkm	union  ccb	  *ccb;
119751433Smarkm	struct ccb_scsiio *csio;
119851433Smarkm
119991244Sdes	ccb = accb->ccb;
120051433Smarkm	csio = &accb->ccb->csio;
120191244Sdes
120291244Sdes	if ((accb->flags & ACCB_ACTIVE) == 0) {
120391244Sdes		device_printf(aha->dev,
120491244Sdes		    "ahadone - Attempt to free non-active ACCB %p\n",
120551433Smarkm		    (void *)accb);
120651433Smarkm		return;
120751433Smarkm	}
120851433Smarkm
120951433Smarkm	if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
121051433Smarkm		bus_dmasync_op_t op;
121151433Smarkm
121251433Smarkm		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
121351433Smarkm			op = BUS_DMASYNC_POSTREAD;
121451433Smarkm		else
121551433Smarkm			op = BUS_DMASYNC_POSTWRITE;
121651433Smarkm		bus_dmamap_sync(aha->buffer_dmat, accb->dmamap, op);
121751433Smarkm		bus_dmamap_unload(aha->buffer_dmat, accb->dmamap);
121851433Smarkm	}
121951433Smarkm
122051433Smarkm	if (accb == aha->recovery_accb) {
122151433Smarkm		/*
122251433Smarkm		 * The recovery ACCB does not have a CCB associated
122351433Smarkm		 * with it, so short circuit the normal error handling.
122451433Smarkm		 * We now traverse our list of pending CCBs and process
122551433Smarkm		 * any that were terminated by the recovery CCBs action.
122651433Smarkm		 * We also reinstate timeouts for all remaining, pending,
122751433Smarkm		 * CCBs.
122851433Smarkm		 */
122951433Smarkm		struct cam_path *path;
123051433Smarkm		struct ccb_hdr *ccb_h;
123151433Smarkm		cam_status error;
123251433Smarkm
123351433Smarkm		/* Notify all clients that a BDR occured */
123451433Smarkm		error = xpt_create_path(&path, /*periph*/NULL,
123551433Smarkm		    cam_sim_path(aha->sim), accb->hccb.target,
123651433Smarkm		    CAM_LUN_WILDCARD);
123751433Smarkm
123851433Smarkm		if (error == CAM_REQ_CMP)
123951433Smarkm			xpt_async(AC_SENT_BDR, path, NULL);
124051433Smarkm
124151433Smarkm		ccb_h = LIST_FIRST(&aha->pending_ccbs);
124251433Smarkm		while (ccb_h != NULL) {
124351433Smarkm			struct aha_ccb *pending_accb;
124451433Smarkm
124551433Smarkm			pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr;
124651433Smarkm			if (pending_accb->hccb.target == accb->hccb.target) {
124751433Smarkm				pending_accb->hccb.ahastat = AHASTAT_HA_BDR;
124851433Smarkm				ccb_h = LIST_NEXT(ccb_h, sim_links.le);
124951433Smarkm				ahadone(aha, pending_accb, AMBI_ERROR);
125051433Smarkm			} else {
125151433Smarkm				ccb_h->timeout_ch = timeout(ahatimeout,
125251433Smarkm				    (caddr_t)pending_accb,
125351433Smarkm				    (ccb_h->timeout * hz) / 1000);
125451433Smarkm				ccb_h = LIST_NEXT(ccb_h, sim_links.le);
125551433Smarkm			}
125667007Sguido		}
125767007Sguido		device_printf(aha->dev, "No longer in timeout\n");
125867007Sguido		return;
125967007Sguido	}
126067007Sguido
126167007Sguido	untimeout(ahatimeout, accb, ccb->ccb_h.timeout_ch);
126267007Sguido
126351433Smarkm	switch (comp_code) {
126451433Smarkm	case AMBI_FREE:
126551433Smarkm		device_printf(aha->dev,
126651433Smarkm		    "ahadone - CCB completed with free status!\n");
126751433Smarkm		break;
126851433Smarkm	case AMBI_NOT_FOUND:
126951433Smarkm		device_printf(aha->dev,
127051433Smarkm		    "ahadone - CCB Abort failed to find CCB\n");
127151433Smarkm		break;
127251433Smarkm	case AMBI_ABORT:
127351433Smarkm	case AMBI_ERROR:
127451433Smarkm		/* An error occured */
127551433Smarkm		if (accb->hccb.opcode < INITIATOR_CCB_WRESID)
127651433Smarkm			csio->resid = 0;
127751433Smarkm		else
127851433Smarkm			csio->resid = aha_a24tou(accb->hccb.data_len);
127951433Smarkm		switch(accb->hccb.ahastat) {
128051433Smarkm		case AHASTAT_DATARUN_ERROR:
128151433Smarkm		{
128251433Smarkm			if (csio->resid <= 0) {
128351433Smarkm				csio->ccb_h.status = CAM_DATA_RUN_ERR;
128451433Smarkm				break;
128551433Smarkm			}
128651433Smarkm			/* FALLTHROUGH */
128751433Smarkm		}
128851433Smarkm		case AHASTAT_NOERROR:
128951433Smarkm			csio->scsi_status = accb->hccb.sdstat;
129051433Smarkm			csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
129151433Smarkm			switch(csio->scsi_status) {
129251433Smarkm			case SCSI_STATUS_CHECK_COND:
129351433Smarkm			case SCSI_STATUS_CMD_TERMINATED:
129451433Smarkm				csio->ccb_h.status |= CAM_AUTOSNS_VALID;
129551433Smarkm				/*
129651433Smarkm				 * The aha writes the sense data at different
129751433Smarkm				 * offsets based on the scsi cmd len
129851433Smarkm				 */
129951433Smarkm				bcopy((caddr_t) &accb->hccb.scsi_cdb +
130051433Smarkm				    accb->hccb.cmd_len,
130174874Smarkm				    (caddr_t) &csio->sense_data,
130251433Smarkm				    accb->hccb.sense_len);
130351433Smarkm				break;
130451433Smarkm			default:
130551433Smarkm				break;
130674874Smarkm			case SCSI_STATUS_OK:
130774874Smarkm				csio->ccb_h.status = CAM_REQ_CMP;
130874874Smarkm				break;
130974874Smarkm			}
131074874Smarkm			break;
131174874Smarkm		case AHASTAT_SELTIMEOUT:
131274874Smarkm			csio->ccb_h.status = CAM_SEL_TIMEOUT;
131374874Smarkm			break;
131474874Smarkm		case AHASTAT_UNEXPECTED_BUSFREE:
131574874Smarkm			csio->ccb_h.status = CAM_UNEXP_BUSFREE;
131674874Smarkm			break;
131751433Smarkm		case AHASTAT_INVALID_PHASE:
131874874Smarkm			csio->ccb_h.status = CAM_SEQUENCE_FAIL;
131974874Smarkm			break;
132074874Smarkm		case AHASTAT_INVALID_ACTION_CODE:
132174874Smarkm			panic("%s: Inavlid Action code", aha_name(aha));
132274874Smarkm			break;
132374874Smarkm		case AHASTAT_INVALID_OPCODE:
132474874Smarkm			if (accb->hccb.opcode < INITIATOR_CCB_WRESID)
132551433Smarkm				panic("%s: Invalid CCB Opcode %x hccb = %p",
132651433Smarkm				    aha_name(aha), accb->hccb.opcode,
132751433Smarkm				    &accb->hccb);
132874874Smarkm			device_printf(aha->dev,
132951433Smarkm			    "AHA-1540A compensation failed\n");
13301592Srgrimes			xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
133190148Simp			csio->ccb_h.status = CAM_REQUEUE_REQ;
13321592Srgrimes			break;
133317435Spst		case AHASTAT_LINKED_CCB_LUN_MISMATCH:
13341592Srgrimes			/* We don't even support linked commands... */
133525101Sdavidn			panic("%s: Linked CCB Lun Mismatch", aha_name(aha));
133625101Sdavidn			break;
133725101Sdavidn		case AHASTAT_INVALID_CCB_OR_SG_PARAM:
133874874Smarkm			panic("%s: Invalid CCB or SG list", aha_name(aha));
133974874Smarkm			break;
134074874Smarkm		case AHASTAT_HA_SCSI_BUS_RESET:
1341110036Syar			if ((csio->ccb_h.status & CAM_STATUS_MASK)
1342109939Syar			    != CAM_CMD_TIMEOUT)
134388763Sache				csio->ccb_h.status = CAM_SCSI_BUS_RESET;
13441592Srgrimes			break;
13451592Srgrimes		case AHASTAT_HA_BDR:
13461592Srgrimes			if ((accb->flags & ACCB_DEVICE_RESET) == 0)
13471592Srgrimes				csio->ccb_h.status = CAM_BDR_SENT;
13481592Srgrimes			else
13491592Srgrimes				csio->ccb_h.status = CAM_CMD_TIMEOUT;
13501592Srgrimes			break;
135117435Spst		}
135217435Spst		if (csio->ccb_h.status != CAM_REQ_CMP) {
135317435Spst			xpt_freeze_devq(csio->ccb_h.path, /*count*/1);
135417435Spst			csio->ccb_h.status |= CAM_DEV_QFRZN;
135574874Smarkm		}
135651433Smarkm		if ((accb->flags & ACCB_RELEASE_SIMQ) != 0)
135789622Sache			ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
135889622Sache		ahafreeccb(aha, accb);
135917435Spst		xpt_done(ccb);
136089622Sache		break;
136189622Sache	case AMBI_OK:
136288763Sache		/* All completed without incident */
136388763Sache		/* XXX DO WE NEED TO COPY SENSE BYTES HERE???? XXX */
136489622Sache		/* I don't think so since it works???? */
136588763Sache		ccb->ccb_h.status |= CAM_REQ_CMP;
136689622Sache		if ((accb->flags & ACCB_RELEASE_SIMQ) != 0)
136789622Sache			ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
136889622Sache		ahafreeccb(aha, accb);
136988763Sache		xpt_done(ccb);
137088763Sache		break;
137188763Sache	}
137288763Sache}
137389622Sache
137417435Spststatic int
137517435Spstahareset(struct aha_softc* aha, int hard_reset)
137617435Spst{
137717435Spst	struct	 ccb_hdr *ccb_h;
137851433Smarkm	u_int	 status;
137917435Spst	u_int	 timeout;
138017435Spst	uint8_t reset_type;
138117435Spst
13821592Srgrimes	if (hard_reset != 0)
1383110691Syar		reset_type = HARD_RESET;
13841592Srgrimes	else
1385110691Syar		reset_type = SOFT_RESET;
1386110691Syar	aha_outb(aha, CONTROL_REG, reset_type);
1387110691Syar
13881592Srgrimes	/* Wait 5sec. for Diagnostic start */
13891592Srgrimes	timeout = 5 * 10000;
1390110691Syar	while (--timeout) {
13911592Srgrimes		status = aha_inb(aha, STATUS_REG);
13921592Srgrimes		if ((status & DIAG_ACTIVE) != 0)
13931592Srgrimes			break;
13941592Srgrimes		DELAY(100);
13951592Srgrimes	}
13961592Srgrimes	if (timeout == 0) {
13971592Srgrimes		PRVERB((aha->dev, "ahareset - Diagnostic Active failed to "
13981592Srgrimes		    "assert. status = %#x\n", status));
13991592Srgrimes		return (ETIMEDOUT);
14001592Srgrimes	}
14011592Srgrimes
14021592Srgrimes	/* Wait 10sec. for Diagnostic end */
14031592Srgrimes	timeout = 10 * 10000;
14041592Srgrimes	while (--timeout) {
14051592Srgrimes		status = aha_inb(aha, STATUS_REG);
140625101Sdavidn		if ((status & DIAG_ACTIVE) == 0)
140725101Sdavidn			break;
140825101Sdavidn		DELAY(100);
140925674Sdavidn	}
141025101Sdavidn	if (timeout == 0) {
141125101Sdavidn		panic("%s: ahareset - Diagnostic Active failed to drop. "
141256668Sshin		    "status = 0x%x\n", aha_name(aha), status);
141356668Sshin		return (ETIMEDOUT);
141499255Sume	}
141525101Sdavidn
141625101Sdavidn	/* Wait for the host adapter to become ready or report a failure */
141725101Sdavidn	timeout = 10000;
141825101Sdavidn	while (--timeout) {
141925101Sdavidn		status = aha_inb(aha, STATUS_REG);
142025101Sdavidn		if ((status & (DIAG_FAIL|HA_READY|DATAIN_REG_READY)) != 0)
142125101Sdavidn			break;
142225101Sdavidn		DELAY(100);
142325101Sdavidn	}
142425101Sdavidn	if (timeout == 0) {
142525101Sdavidn		device_printf(aha->dev, "ahareset - Host adapter failed to "
142625101Sdavidn		    "come ready. status = 0x%x\n", status);
142725101Sdavidn		return (ETIMEDOUT);
142825101Sdavidn	}
142925101Sdavidn
143025101Sdavidn	/* If the diagnostics failed, tell the user */
143140310Sdes	if ((status & DIAG_FAIL) != 0
1432105877Srwatson	 || (status & HA_READY) == 0) {
143325101Sdavidn		device_printf(aha->dev, "ahareset - Adapter failed diag\n");
143440310Sdes
14351592Srgrimes		if ((status & DATAIN_REG_READY) != 0)
143625101Sdavidn			device_printf(aha->dev, "ahareset - Host Adapter "
14371592Srgrimes			    "Error code = 0x%x\n", aha_inb(aha, DATAIN_REG));
143874874Smarkm		return (ENXIO);
143974874Smarkm	}
144074874Smarkm
144174874Smarkm	/* If we've attached to the XPT, tell it about the event */
144274874Smarkm	if (aha->path != NULL)
144374874Smarkm		xpt_async(AC_BUS_RESET, aha->path, NULL);
144474874Smarkm
144574874Smarkm	/*
144674874Smarkm	 * Perform completion processing for all outstanding CCBs.
144774874Smarkm	 */
14481592Srgrimes	while ((ccb_h = LIST_FIRST(&aha->pending_ccbs)) != NULL) {
1449102311Syar		struct aha_ccb *pending_accb;
1450102311Syar
1451102311Syar		pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr;
14521592Srgrimes		pending_accb->hccb.ahastat = AHASTAT_HA_SCSI_BUS_RESET;
14531592Srgrimes		ahadone(aha, pending_accb, AMBI_ERROR);
145417435Spst	}
145525283Sdavidn
145625283Sdavidn	/* If we've allocated mailboxes, initialize them */
145725283Sdavidn	/* Must be done after we've aborted our queue, or aha_cmd fails */
14586740Sguido	if (aha->init_level > 4)
145925283Sdavidn		ahainitmboxes(aha);
14606740Sguido
14616740Sguido	return (0);
146225101Sdavidn}
1463109939Syar
146425101Sdavidn/*
1465109893Syar * Send a command to the adapter.
146625101Sdavidn */
1467109893Syarint
1468110036Syaraha_cmd(struct aha_softc *aha, aha_op_t opcode, uint8_t *params,
1469110036Syar	u_int param_len, uint8_t *reply_data, u_int reply_len,
1470110036Syar	u_int cmd_timeout)
1471110036Syar{
1472110036Syar	u_int	timeout;
1473110036Syar	u_int	status;
1474110036Syar	u_int	saved_status;
1475110036Syar	u_int	intstat;
1476117349Syar	u_int	reply_buf_size;
1477117349Syar	int	s;
1478117349Syar	int	cmd_complete;
1479117349Syar	int	error;
1480117349Syar
1481110036Syar	/* No data returned to start */
1482110036Syar	reply_buf_size = reply_len;
1483110036Syar	reply_len = 0;
1484110036Syar	intstat = 0;
14851592Srgrimes	cmd_complete = 0;
1486110036Syar	saved_status = 0;
1487110036Syar	error = 0;
14881592Srgrimes
1489110036Syar	/*
1490110036Syar	 * All commands except for the "start mailbox" and the "enable
1491110036Syar	 * outgoing mailbox read interrupt" commands cannot be issued
1492110036Syar	 * while there are pending transactions.  Freeze our SIMQ
1493110036Syar	 * and wait for all completions to occur if necessary.
1494110036Syar	 */
1495110036Syar	timeout = 10000;
1496110036Syar	s = splcam();
1497110036Syar	while (LIST_FIRST(&aha->pending_ccbs) != NULL && --timeout) {
1498110036Syar		/* Fire the interrupt handler in case interrupts are blocked */
1499110036Syar		aha_intr(aha);
1500110036Syar		splx(s);
1501109893Syar		DELAY(10);
1502110036Syar		s = splcam();
1503110036Syar	}
1504110036Syar	splx(s);
1505110036Syar
1506110036Syar	if (timeout == 0) {
1507110036Syar		device_printf(aha->dev,
1508110036Syar		    "aha_cmd: Timeout waiting for adapter idle\n");
1509109939Syar		return (ETIMEDOUT);
1510110036Syar	}
1511110036Syar	aha->command_cmp = 0;
1512110036Syar	/*
1513110036Syar	 * Wait up to 10 sec. for the adapter to become
151417435Spst	 * ready to accept commands.
151517435Spst	 */
151617435Spst	timeout = 100000;
1517110036Syar	while (--timeout) {
1518110036Syar		status = aha_inb(aha, STATUS_REG);
1519110036Syar		if ((status & HA_READY) != 0 && (status & CMD_REG_BUSY) == 0)
1520110036Syar			break;
1521110036Syar		/*
1522110036Syar		 * Throw away any pending data which may be
1523110036Syar		 * left over from earlier commands that we
1524110036Syar		 * timedout on.
1525110036Syar		 */
15261592Srgrimes		if ((status & DATAIN_REG_READY) != 0)
15271592Srgrimes			(void)aha_inb(aha, DATAIN_REG);
15281592Srgrimes		DELAY(100);
15291592Srgrimes	}
1530110036Syar	if (timeout == 0) {
1531110036Syar		device_printf(aha->dev, "aha_cmd: Timeout waiting for adapter"
1532110036Syar		    " ready, status = 0x%x\n", status);
1533110036Syar		return (ETIMEDOUT);
1534110036Syar	}
1535110036Syar
1536110036Syar	/*
1537110036Syar	 * Send the opcode followed by any necessary parameter bytes.
1538110036Syar	 */
1539110036Syar	aha_outb(aha, COMMAND_REG, opcode);
1540110036Syar
1541110036Syar	/*
15428696Sdg	 * Wait for up to 1sec to get the parameter list sent
15431592Srgrimes	 */
15441592Srgrimes	timeout = 10000;
15451592Srgrimes	while (param_len && --timeout) {
15461592Srgrimes		DELAY(100);
154725283Sdavidn		s = splcam();
154825283Sdavidn		status = aha_inb(aha, STATUS_REG);
154925283Sdavidn		intstat = aha_inb(aha, INTSTAT_REG);
15501592Srgrimes		splx(s);
155125283Sdavidn
15521592Srgrimes		if ((intstat & (INTR_PENDING|CMD_COMPLETE))
15531592Srgrimes		 == (INTR_PENDING|CMD_COMPLETE)) {
15541592Srgrimes			saved_status = status;
15551592Srgrimes			cmd_complete = 1;
15561592Srgrimes			break;
15571592Srgrimes		}
15581592Srgrimes
15591592Srgrimes		if (aha->command_cmp != 0) {
15601592Srgrimes			saved_status = aha->latched_status;
15611592Srgrimes			cmd_complete = 1;
15621592Srgrimes			break;
15636740Sguido		}
15646740Sguido		if ((status & DATAIN_REG_READY) != 0)
156517433Spst			break;
156617433Spst		if ((status & CMD_REG_BUSY) == 0) {
156776096Smarkm			aha_outb(aha, COMMAND_REG, *params++);
156817433Spst			param_len--;
15691592Srgrimes			timeout = 10000;
15701592Srgrimes		}
157125283Sdavidn	}
157225283Sdavidn	if (timeout == 0) {
157325283Sdavidn		device_printf(aha->dev, "aha_cmd: Timeout sending parameters, "
157483308Smikeh		    "status = 0x%x\n", status);
157583308Smikeh		error = ETIMEDOUT;
157625283Sdavidn	}
157725283Sdavidn
157825283Sdavidn	/*
157983308Smikeh	 * For all other commands, we wait for any output data
158013139Speter	 * and the final comand completion interrupt.
15811592Srgrimes	 */
15821592Srgrimes	while (cmd_complete == 0 && --cmd_timeout) {
15831592Srgrimes
15841592Srgrimes		s = splcam();
15851592Srgrimes		status = aha_inb(aha, STATUS_REG);
158684841Syar		intstat = aha_inb(aha, INTSTAT_REG);
158784841Syar		splx(s);
158884841Syar
158984841Syar		if (aha->command_cmp != 0) {
159084841Syar			cmd_complete = 1;
159125986Sdanny			saved_status = aha->latched_status;
15921592Srgrimes		} else if ((intstat & (INTR_PENDING|CMD_COMPLETE))
15931592Srgrimes			== (INTR_PENDING|CMD_COMPLETE)) {
159484842Syar			/*
159513139Speter			 * Our poll (in case interrupts are blocked)
15961592Srgrimes			 * saw the CMD_COMPLETE interrupt.
15971592Srgrimes			 */
15981592Srgrimes			cmd_complete = 1;
15991592Srgrimes			saved_status = status;
16001592Srgrimes		}
160125101Sdavidn		if ((status & DATAIN_REG_READY) != 0) {
160225101Sdavidn			uint8_t data;
160325101Sdavidn
1604110036Syar			data = aha_inb(aha, DATAIN_REG);
1605110036Syar			if (reply_len < reply_buf_size) {
1606110036Syar				*reply_data++ = data;
1607110036Syar			} else {
16081592Srgrimes				device_printf(aha->dev,
16091592Srgrimes				    "aha_cmd - Discarded reply data "
16101592Srgrimes				    "byte for opcode 0x%x\n", opcode);
161125101Sdavidn			}
161225101Sdavidn			/*
161325101Sdavidn			 * Reset timeout to ensure at least a second
1614110036Syar			 * between response bytes.
1615110036Syar			 */
1616110036Syar			cmd_timeout = MAX(cmd_timeout, 10000);
1617110036Syar			reply_len++;
16181592Srgrimes		}
16191592Srgrimes		DELAY(100);
16201592Srgrimes	}
16211592Srgrimes	if (cmd_timeout == 0) {
162290148Simp		device_printf(aha->dev, "aha_cmd: Timeout: status = 0x%x, "
16231592Srgrimes		    "intstat = 0x%x, reply_len = %d\n", status, intstat,
16241592Srgrimes		    reply_len);
16251592Srgrimes		return (ETIMEDOUT);
162690148Simp	}
162736612Sjb
16281592Srgrimes	/*
16291592Srgrimes	 * Clear any pending interrupts.  Block interrupts so our
16301592Srgrimes	 * interrupt handler is not re-entered.
16311592Srgrimes	 */
16321592Srgrimes	s = splcam();
16331592Srgrimes	aha_intr(aha);
16341592Srgrimes	splx(s);
163531973Simp
16361592Srgrimes	if (error != 0)
16371592Srgrimes		return (error);
16381592Srgrimes
16391592Srgrimes	/*
16401592Srgrimes	 * If the command was rejected by the controller, tell the caller.
16411592Srgrimes	 */
16421592Srgrimes	if ((saved_status & CMD_INVALID) != 0) {
16431592Srgrimes		PRVERB((aha->dev, "Invalid Command 0x%x\n", opcode));
16441592Srgrimes		/*
16451592Srgrimes		 * Some early adapters may not recover properly from
16461592Srgrimes		 * an invalid command.  If it appears that the controller
16471592Srgrimes		 * has wedged (i.e. status was not cleared by our interrupt
16481592Srgrimes		 * reset above), perform a soft reset.
16491592Srgrimes      		 */
1650110144Syar		DELAY(1000);
1651110144Syar		status = aha_inb(aha, STATUS_REG);
1652110144Syar		if ((status & (CMD_INVALID|STATUS_REG_RSVD|DATAIN_REG_READY|
1653110144Syar			      CMD_REG_BUSY|DIAG_FAIL|DIAG_ACTIVE)) != 0
1654110144Syar		 || (status & (HA_READY|INIT_REQUIRED))
1655110144Syar		  != (HA_READY|INIT_REQUIRED))
1656125565Syar			ahareset(aha, /*hard_reset*/FALSE);
1657125565Syar		return (EINVAL);
1658125565Syar	}
1659125565Syar
1660125565Syar	if (param_len > 0) {
1661125565Syar		/* The controller did not accept the full argument list */
1662125565Syar		PRVERB((aha->dev, "Controller did not accept full argument "
1663125565Syar		    "list (%d > 0)\n", param_len));
1664110144Syar	 	return (E2BIG);
1665110144Syar	}
1666110144Syar
1667110144Syar	if (reply_len != reply_buf_size) {
1668110144Syar		/* Too much or too little data received */
1669110144Syar		PRVERB((aha->dev, "data received mismatch (%d != %d)\n",
16701592Srgrimes		    reply_len, reply_buf_size));
16711592Srgrimes		return (EMSGSIZE);
16721592Srgrimes	}
16731592Srgrimes
16741592Srgrimes	/* We were successful */
16751592Srgrimes	return (0);
16761592Srgrimes}
16771592Srgrimes
16781592Srgrimesstatic int
16791592Srgrimesahainitmboxes(struct aha_softc *aha)
16801592Srgrimes{
16811592Srgrimes	int error;
16821592Srgrimes	init_24b_mbox_params_t init_mbox;
16831592Srgrimes
16841592Srgrimes	bzero(aha->in_boxes, sizeof(aha_mbox_in_t) * aha->num_boxes);
16851592Srgrimes	bzero(aha->out_boxes, sizeof(aha_mbox_out_t) * aha->num_boxes);
16861592Srgrimes	aha->cur_inbox = aha->in_boxes;
16871592Srgrimes	aha->last_inbox = aha->in_boxes + aha->num_boxes - 1;
16881592Srgrimes	aha->cur_outbox = aha->out_boxes;
16891592Srgrimes	aha->last_outbox = aha->out_boxes + aha->num_boxes - 1;
16901592Srgrimes
16911592Srgrimes	/* Tell the adapter about them */
16921592Srgrimes	init_mbox.num_mboxes = aha->num_boxes;
16931592Srgrimes	ahautoa24(aha->mailbox_physbase, init_mbox.base_addr);
16946740Sguido	error = aha_cmd(aha, AOP_INITIALIZE_MBOX, (uint8_t *)&init_mbox,
16958240Swollman	    /*parmlen*/sizeof(init_mbox), /*reply_buf*/NULL,
16968240Swollman	    /*reply_len*/0, DEFAULT_CMD_TIMEOUT);
16976740Sguido
169817433Spst	if (error != 0)
16991592Srgrimes		printf("ahainitmboxes: Initialization command failed\n");
17001592Srgrimes	return (error);
17011592Srgrimes}
17021592Srgrimes
17031592Srgrimes/*
17041592Srgrimes * Update the XPT's idea of the negotiated transfer
17051592Srgrimes * parameters for a particular target.
17061592Srgrimes */
17071592Srgrimesstatic void
17081592Srgrimesahafetchtransinfo(struct aha_softc *aha, struct ccb_trans_settings* cts)
170990148Simp{
17101592Srgrimes	setup_data_t	setup_info;
1711101537Syar	u_int		target;
17121592Srgrimes	u_int		targ_offset;
171390148Simp	u_int		sync_period;
17141592Srgrimes	int		error;
1715101537Syar	uint8_t	param;
1716101537Syar	targ_syncinfo_t	sync_info;
1717101537Syar#ifdef	CAM_NEW_TRAN_CODE
1718101537Syar	struct ccb_trans_settings_spi *spi = &cts->xport_specific.spi;
1719101537Syar#endif
1720101537Syar
1721101537Syar	target = cts->ccb_h.target_id;
1722101537Syar	targ_offset = (target & 0x7);
1723101537Syar
1724101537Syar	/*
1725101537Syar	 * Inquire Setup Information.  This command retreives
17261592Srgrimes	 * the sync info for older models.
1727101537Syar	 */
1728101537Syar	param = sizeof(setup_info);
1729101537Syar	error = aha_cmd(aha, AOP_INQUIRE_SETUP_INFO, &param, /*paramlen*/1,
1730101537Syar	    (uint8_t*)&setup_info, sizeof(setup_info), DEFAULT_CMD_TIMEOUT);
1731101537Syar
1732101537Syar	if (error != 0) {
1733101537Syar		device_printf(aha->dev,
1734101537Syar		    "ahafetchtransinfo - Inquire Setup Info Failed %d\n",
1735101537Syar		    error);
17361592Srgrimes		return;
17371592Srgrimes	}
1738101537Syar
1739101537Syar	sync_info = setup_info.syncinfo[targ_offset];
1740101537Syar
1741101537Syar#ifdef	CAM_NEW_TRAN_CODE
1742101537Syar	if (sync_info.sync == 0)
1743101537Syar		spi->sync_offset = 0;
1744101537Syar	else
17451592Srgrimes		spi->sync_offset = sync_info.offset;
17461592Srgrimes
17471592Srgrimes	spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
1748101537Syar
17491592Srgrimes	if (aha->boardid >= BOARD_1542CF)
17501592Srgrimes		sync_period = 1000;
17511592Srgrimes	else
17521592Srgrimes		sync_period = 2000;
17531592Srgrimes	sync_period += 500 * sync_info.period;
17541592Srgrimes
17551592Srgrimes	/* Convert ns value to standard SCSI sync rate */
17561592Srgrimes	if (spi->sync_offset != 0)
17571592Srgrimes		spi->sync_period = scsi_calc_syncparam(sync_period);
17581592Srgrimes	else
17591592Srgrimes		spi->sync_period = 0;
17601592Srgrimes
17611592Srgrimes	spi->valid = CTS_SPI_VALID_SYNC_RATE
17621592Srgrimes		   | CTS_SPI_VALID_SYNC_OFFSET
17631592Srgrimes		   | CTS_SPI_VALID_BUS_WIDTH;
17641592Srgrimes#else
17651592Srgrimes	if (sync_info.sync == 0)
17661592Srgrimes		cts->sync_offset = 0;
17671592Srgrimes	else
17681592Srgrimes		cts->sync_offset = sync_info.offset;
17691592Srgrimes
17701592Srgrimes	cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
177182792Sache
17721592Srgrimes	if (aha->boardid >= BOARD_1542CF)
17731592Srgrimes		sync_period = 1000;
17741592Srgrimes	else
17751592Srgrimes		sync_period = 2000;
17761592Srgrimes	sync_period += 500 * sync_info.period;
17771592Srgrimes
17781592Srgrimes	/* Convert ns value to standard SCSI sync rate */
17791592Srgrimes	if (cts->sync_offset != 0)
17801592Srgrimes		cts->sync_period = scsi_calc_syncparam(sync_period);
17811592Srgrimes	else
17821592Srgrimes		cts->sync_period = 0;
17831592Srgrimes
17841592Srgrimes	cts->valid = CCB_TRANS_SYNC_RATE_VALID
17851592Srgrimes		   | CCB_TRANS_SYNC_OFFSET_VALID
17861592Srgrimes		   | CCB_TRANS_BUS_WIDTH_VALID;
17871592Srgrimes#endif
17881592Srgrimes        xpt_async(AC_TRANSFER_NEG, cts->ccb_h.path, cts);
17891592Srgrimes}
17901592Srgrimes
17911592Srgrimesstatic void
17921592Srgrimesahamapmboxes(void *arg, bus_dma_segment_t *segs, int nseg, int error)
17931592Srgrimes{
1794102566Syar	struct aha_softc* aha;
17951592Srgrimes
1796101537Syar	aha = (struct aha_softc*)arg;
1797101537Syar	aha->mailbox_physbase = segs->ds_addr;
1798101537Syar}
1799101537Syar
18001592Srgrimesstatic void
18011592Srgrimesahamapccbs(void *arg, bus_dma_segment_t *segs, int nseg, int error)
18021592Srgrimes{
180390148Simp	struct aha_softc* aha;
18041592Srgrimes
18051592Srgrimes	aha = (struct aha_softc*)arg;
18061592Srgrimes	aha->aha_ccb_physbase = segs->ds_addr;
18071592Srgrimes}
18081592Srgrimes
18091592Srgrimesstatic void
181056668Sshinahamapsgs(void *arg, bus_dma_segment_t *segs, int nseg, int error)
181156668Sshin{
18121592Srgrimes
18131592Srgrimes	struct aha_softc* aha;
1814100612Syar
1815100609Syar	aha = (struct aha_softc*)arg;
18161592Srgrimes	SLIST_FIRST(&aha->sg_maps)->sg_physaddr = segs->ds_addr;
181756668Sshin}
1818109742Syar
18191592Srgrimesstatic void
18201592Srgrimesahapoll(struct cam_sim *sim)
182156668Sshin{
18221592Srgrimes	aha_intr(cam_sim_softc(sim));
18231592Srgrimes}
18241592Srgrimes
18251592Srgrimesstatic void
18261592Srgrimesahatimeout(void *arg)
18271592Srgrimes{
18281592Srgrimes	struct aha_ccb	*accb;
182956668Sshin	union  ccb	*ccb;
183056668Sshin	struct aha_softc *aha;
18311592Srgrimes	int		 s;
1832100612Syar	uint32_t	paddr;
1833100609Syar	struct ccb_hdr *ccb_h;
183456668Sshin
18351592Srgrimes	accb = (struct aha_ccb *)arg;
18368240Swollman	ccb = accb->ccb;
18378240Swollman	aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr;
18388240Swollman	xpt_print_path(ccb->ccb_h.path);
18398240Swollman	printf("CCB %p - timed out\n", (void *)accb);
18408240Swollman
18418240Swollman	s = splcam();
18428240Swollman
18438240Swollman	if ((accb->flags & ACCB_ACTIVE) == 0) {
1844100612Syar		xpt_print_path(ccb->ccb_h.path);
1845100609Syar		printf("CCB %p - timed out CCB already completed\n",
18468240Swollman		    (void *)accb);
18478240Swollman		splx(s);
18488240Swollman		return;
1849100612Syar	}
1850100609Syar
18518240Swollman	/*
18528240Swollman	 * In order to simplify the recovery process, we ask the XPT
18531592Srgrimes	 * layer to halt the queue of new transactions and we traverse
18541592Srgrimes	 * the list of pending CCBs and remove their timeouts. This
18551592Srgrimes	 * means that the driver attempts to clear only one error
18561592Srgrimes	 * condition at a time.  In general, timeouts that occur
18571592Srgrimes	 * close together are related anyway, so there is no benefit
18581592Srgrimes	 * in attempting to handle errors in parrallel.  Timeouts will
18591592Srgrimes	 * be reinstated when the recovery process ends.
18601592Srgrimes	 */
18611592Srgrimes	if ((accb->flags & ACCB_DEVICE_RESET) == 0) {
18621592Srgrimes		if ((accb->flags & ACCB_RELEASE_SIMQ) == 0) {
18631592Srgrimes			xpt_freeze_simq(aha->sim, /*count*/1);
186490148Simp			accb->flags |= ACCB_RELEASE_SIMQ;
18651592Srgrimes		}
18661592Srgrimes
18671592Srgrimes		ccb_h = LIST_FIRST(&aha->pending_ccbs);
1868109611Scjc		while (ccb_h != NULL) {
18691592Srgrimes			struct aha_ccb *pending_accb;
18701592Srgrimes
18711592Srgrimes			pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr;
18721592Srgrimes			untimeout(ahatimeout, pending_accb, ccb_h->timeout_ch);
187331973Simp			ccb_h = LIST_NEXT(ccb_h, sim_links.le);
18741592Srgrimes		}
187531973Simp	}
18761592Srgrimes
187756668Sshin	if ((accb->flags & ACCB_DEVICE_RESET) != 0
187886628Syar	 || aha->cur_outbox->action_code != AMBO_FREE) {
187956668Sshin		/*
188012532Sguido		 * Try a full host adapter/SCSI bus reset.
188112532Sguido		 * We do this only if we have already attempted
18821592Srgrimes		 * to clear the condition with a BDR, or we cannot
188312532Sguido		 * attempt a BDR for lack of mailbox resources.
188412532Sguido		 */
188512532Sguido		ccb->ccb_h.status = CAM_CMD_TIMEOUT;
188612532Sguido		ahareset(aha, /*hardreset*/TRUE);
188712532Sguido		device_printf(aha->dev, "No longer in timeout\n");
188812532Sguido	} else {
188986628Syar		/*
189086628Syar		 * Send a Bus Device Reset message:
189186628Syar		 * The target that is holding up the bus may not
189286628Syar		 * be the same as the one that triggered this timeout
189386628Syar		 * (different commands have different timeout lengths),
189486628Syar		 * but we have no way of determining this from our
189586628Syar		 * timeout handler.  Our strategy here is to queue a
189686628Syar		 * BDR message to the target of the timed out command.
189786628Syar		 * If this fails, we'll get another timeout 2 seconds
189886628Syar		 * later which will attempt a bus reset.
189986628Syar		 */
190086628Syar		accb->flags |= ACCB_DEVICE_RESET;
19011592Srgrimes		ccb->ccb_h.timeout_ch = timeout(ahatimeout, (caddr_t)accb, 2 * hz);
19021592Srgrimes		aha->recovery_accb->hccb.opcode = INITIATOR_BUS_DEV_RESET;
190386628Syar
1904101809Syar		/* No Data Transfer */
1905101809Syar		aha->recovery_accb->hccb.datain = TRUE;
190686628Syar		aha->recovery_accb->hccb.dataout = TRUE;
190786628Syar		aha->recovery_accb->hccb.ahastat = 0;
190886628Syar		aha->recovery_accb->hccb.sdstat = 0;
190986628Syar		aha->recovery_accb->hccb.target = ccb->ccb_h.target_id;
19101592Srgrimes
191156668Sshin		/* Tell the adapter about this command */
191256668Sshin		paddr = ahaccbvtop(aha, aha->recovery_accb);
191317435Spst		ahautoa24(paddr, aha->cur_outbox->ccb_addr);
1914100612Syar		aha->cur_outbox->action_code = AMBO_START;
1915100609Syar		aha_outb(aha, COMMAND_REG, AOP_START_MBOX);
191656668Sshin		ahanextoutbox(aha);
19171592Srgrimes	}
19181592Srgrimes
19191592Srgrimes	splx(s);
19201592Srgrimes}
192186628Syar
192286628Syarint
192386628Syaraha_detach(struct aha_softc *aha)
192486628Syar{
192586628Syar	xpt_async(AC_LOST_DEVICE, aha->path, NULL);
19261592Srgrimes	xpt_free_path(aha->path);
19271592Srgrimes	xpt_bus_deregister(cam_sim_path(aha->sim));
19281592Srgrimes	cam_sim_free(aha->sim, /*free_devq*/TRUE);
19291592Srgrimes	return (0);
19301592Srgrimes}
19311592Srgrimes