aic7xxx_osm.c revision 150450
1139749Simp/*-
2123579Sgibbs * Bus independent FreeBSD shim for the aic7xxx based Adaptec SCSI controllers
365942Sgibbs *
471717Sgibbs * Copyright (c) 1994-2001 Justin T. Gibbs.
565942Sgibbs * All rights reserved.
665942Sgibbs *
765942Sgibbs * Redistribution and use in source and binary forms, with or without
865942Sgibbs * modification, are permitted provided that the following conditions
965942Sgibbs * are met:
1065942Sgibbs * 1. Redistributions of source code must retain the above copyright
1165942Sgibbs *    notice, this list of conditions, and the following disclaimer,
1265942Sgibbs *    without modification.
1365942Sgibbs * 2. The name of the author may not be used to endorse or promote products
1465942Sgibbs *    derived from this software without specific prior written permission.
1565942Sgibbs *
1665942Sgibbs * Alternatively, this software may be distributed under the terms of the
1765942Sgibbs * GNU Public License ("GPL").
1865942Sgibbs *
1965942Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2065942Sgibbs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2165942Sgibbs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2265942Sgibbs * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
2365942Sgibbs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2465942Sgibbs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2565942Sgibbs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2665942Sgibbs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2765942Sgibbs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2865942Sgibbs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2965942Sgibbs * SUCH DAMAGE.
3065942Sgibbs *
31123579Sgibbs * $Id: //depot/aic7xxx/freebsd/dev/aic7xxx/aic7xxx_osm.c#20 $
3265942Sgibbs */
3365942Sgibbs
34119418Sobrien#include <sys/cdefs.h>
35119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/aic7xxx/aic7xxx_osm.c 150450 2005-09-22 05:01:37Z gibbs $");
36119418Sobrien
3795378Sgibbs#include <dev/aic7xxx/aic7xxx_osm.h>
3865942Sgibbs#include <dev/aic7xxx/aic7xxx_inline.h>
3965942Sgibbs
40123579Sgibbs#include <sys/kthread.h>
41123579Sgibbs
4265942Sgibbs#ifndef AHC_TMODE_ENABLE
4365942Sgibbs#define AHC_TMODE_ENABLE 0
4465942Sgibbs#endif
4565942Sgibbs
46123579Sgibbs#include <dev/aic7xxx/aic_osm_lib.c>
47123579Sgibbs
4865942Sgibbs#define ccb_scb_ptr spriv_ptr0
4965942Sgibbs
50103811Sscottldevclass_t ahc_devclass;
51103811Sscottl
5265942Sgibbs#if UNUSED
5365942Sgibbsstatic void	ahc_dump_targcmd(struct target_cmd *cmd);
5465942Sgibbs#endif
5576634Sgibbsstatic int	ahc_modevent(module_t mod, int type, void *data);
5665942Sgibbsstatic void	ahc_action(struct cam_sim *sim, union ccb *ccb);
5765942Sgibbsstatic void	ahc_get_tran_settings(struct ahc_softc *ahc,
5865942Sgibbs				      int our_id, char channel,
5965942Sgibbs				      struct ccb_trans_settings *cts);
6065942Sgibbsstatic void	ahc_async(void *callback_arg, uint32_t code,
6165942Sgibbs			  struct cam_path *path, void *arg);
6265942Sgibbsstatic void	ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs,
6365942Sgibbs				int nsegments, int error);
6465942Sgibbsstatic void	ahc_poll(struct cam_sim *sim);
6565942Sgibbsstatic void	ahc_setup_data(struct ahc_softc *ahc, struct cam_sim *sim,
6665942Sgibbs			       struct ccb_scsiio *csio, struct scb *scb);
6765942Sgibbsstatic void	ahc_abort_ccb(struct ahc_softc *ahc, struct cam_sim *sim,
6865942Sgibbs			      union ccb *ccb);
6965942Sgibbsstatic int	ahc_create_path(struct ahc_softc *ahc,
7066269Sgibbs				char channel, u_int target, u_int lun,
7165942Sgibbs				struct cam_path **path);
7265942Sgibbs
7365942Sgibbs
7465942Sgibbsstatic int
7566269Sgibbsahc_create_path(struct ahc_softc *ahc, char channel, u_int target,
7666269Sgibbs	        u_int lun, struct cam_path **path)
7765942Sgibbs{
7865942Sgibbs	path_id_t path_id;
7965942Sgibbs
8066269Sgibbs	if (channel == 'B')
8165942Sgibbs		path_id = cam_sim_path(ahc->platform_data->sim_b);
8265942Sgibbs	else
8365942Sgibbs		path_id = cam_sim_path(ahc->platform_data->sim);
8465942Sgibbs
8565942Sgibbs	return (xpt_create_path(path, /*periph*/NULL,
8666269Sgibbs				path_id, target, lun));
8765942Sgibbs}
8865942Sgibbs
8995378Sgibbsint
9095378Sgibbsahc_map_int(struct ahc_softc *ahc)
9195378Sgibbs{
9295378Sgibbs	int error;
93133911Sgibbs	int zero;
94133911Sgibbs	int shareable;
9595378Sgibbs
96133911Sgibbs	zero = 0;
97133911Sgibbs	shareable = (ahc->flags & AHC_EDGE_INTERRUPT) ? 0: RF_SHAREABLE;
98133911Sgibbs	ahc->platform_data->irq =
99133911Sgibbs	    bus_alloc_resource_any(ahc->dev_softc, SYS_RES_IRQ, &zero,
100133911Sgibbs				   RF_ACTIVE | shareable);
101133911Sgibbs	if (ahc->platform_data->irq == NULL) {
102133911Sgibbs		device_printf(ahc->dev_softc,
103133911Sgibbs			      "bus_alloc_resource() failed to allocate IRQ\n");
104133911Sgibbs		return (ENOMEM);
105133911Sgibbs	}
106133911Sgibbs	ahc->platform_data->irq_res_type = SYS_RES_IRQ;
107133911Sgibbs
10895378Sgibbs	/* Hook up our interrupt handler */
10995378Sgibbs	error = bus_setup_intr(ahc->dev_softc, ahc->platform_data->irq,
11095378Sgibbs			       INTR_TYPE_CAM, ahc_platform_intr, ahc,
11195378Sgibbs			       &ahc->platform_data->ih);
11295378Sgibbs
11395378Sgibbs	if (error != 0)
11495378Sgibbs		device_printf(ahc->dev_softc, "bus_setup_intr() failed: %d\n",
11595378Sgibbs			      error);
11695378Sgibbs	return (error);
11795378Sgibbs}
11895378Sgibbs
119133911Sgibbsint
120133911Sgibbsaic7770_map_registers(struct ahc_softc *ahc, u_int unused_ioport_arg)
121133911Sgibbs{
122133911Sgibbs	struct	resource *regs;
123133911Sgibbs	int	rid;
124133911Sgibbs
125133911Sgibbs	rid = 0;
126133911Sgibbs	regs = bus_alloc_resource_any(ahc->dev_softc, SYS_RES_IOPORT, &rid,
127133911Sgibbs				      RF_ACTIVE);
128133911Sgibbs	if (regs == NULL) {
129133911Sgibbs		device_printf(ahc->dev_softc, "Unable to map I/O space?!\n");
130133911Sgibbs		return ENOMEM;
131133911Sgibbs	}
132133911Sgibbs	ahc->platform_data->regs_res_type = SYS_RES_IOPORT;
133133911Sgibbs	ahc->platform_data->regs_res_id = rid,
134133911Sgibbs	ahc->platform_data->regs = regs;
135133911Sgibbs	ahc->tag = rman_get_bustag(regs);
136133911Sgibbs	ahc->bsh = rman_get_bushandle(regs);
137133911Sgibbs	return (0);
138133911Sgibbs}
139133911Sgibbs
14065942Sgibbs/*
14165942Sgibbs * Attach all the sub-devices we can find
14265942Sgibbs */
14365942Sgibbsint
14465942Sgibbsahc_attach(struct ahc_softc *ahc)
14565942Sgibbs{
14665942Sgibbs	char   ahc_info[256];
14765942Sgibbs	struct ccb_setasync csa;
14865942Sgibbs	struct cam_devq *devq;
14965942Sgibbs	int bus_id;
15065942Sgibbs	int bus_id2;
15165942Sgibbs	struct cam_sim *sim;
15265942Sgibbs	struct cam_sim *sim2;
15365942Sgibbs	struct cam_path *path;
15465942Sgibbs	struct cam_path *path2;
15565942Sgibbs	long s;
15665942Sgibbs	int count;
15765942Sgibbs
15865942Sgibbs	count = 0;
15965942Sgibbs	sim = NULL;
16065942Sgibbs	sim2 = NULL;
16165942Sgibbs
162123579Sgibbs	/*
163123579Sgibbs	 * Create a thread to perform all recovery.
164123579Sgibbs	 */
165123579Sgibbs	if (ahc_spawn_recovery_thread(ahc) != 0)
166123579Sgibbs		goto fail;
167123579Sgibbs
16865942Sgibbs	ahc_controller_info(ahc, ahc_info);
16965942Sgibbs	printf("%s\n", ahc_info);
17065942Sgibbs	ahc_lock(ahc, &s);
171123579Sgibbs
17265942Sgibbs	/*
17365942Sgibbs	 * Attach secondary channel first if the user has
17465942Sgibbs	 * declared it the primary channel.
17565942Sgibbs	 */
17672552Sgibbs	if ((ahc->features & AHC_TWIN) != 0
17774094Sgibbs	 && (ahc->flags & AHC_PRIMARY_CHANNEL) != 0) {
17865942Sgibbs		bus_id = 1;
17965942Sgibbs		bus_id2 = 0;
18065942Sgibbs	} else {
18165942Sgibbs		bus_id = 0;
18265942Sgibbs		bus_id2 = 1;
18365942Sgibbs	}
18465942Sgibbs
18565942Sgibbs	/*
18665942Sgibbs	 * Create the device queue for our SIM(s).
18765942Sgibbs	 */
18871390Sgibbs	devq = cam_simq_alloc(AHC_MAX_QUEUE);
18965942Sgibbs	if (devq == NULL)
19065942Sgibbs		goto fail;
19165942Sgibbs
19265942Sgibbs	/*
19365942Sgibbs	 * Construct our first channel SIM entry
19465942Sgibbs	 */
19566104Sgibbs	sim = cam_sim_alloc(ahc_action, ahc_poll, "ahc", ahc,
19666104Sgibbs			    device_get_unit(ahc->dev_softc),
19771390Sgibbs			    1, AHC_MAX_QUEUE, devq);
19865942Sgibbs	if (sim == NULL) {
19965942Sgibbs		cam_simq_free(devq);
20065942Sgibbs		goto fail;
20165942Sgibbs	}
20265942Sgibbs
20365942Sgibbs	if (xpt_bus_register(sim, bus_id) != CAM_SUCCESS) {
20465942Sgibbs		cam_sim_free(sim, /*free_devq*/TRUE);
20565942Sgibbs		sim = NULL;
20665942Sgibbs		goto fail;
20765942Sgibbs	}
20865942Sgibbs
20965942Sgibbs	if (xpt_create_path(&path, /*periph*/NULL,
21065942Sgibbs			    cam_sim_path(sim), CAM_TARGET_WILDCARD,
21165942Sgibbs			    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
21265942Sgibbs		xpt_bus_deregister(cam_sim_path(sim));
21365942Sgibbs		cam_sim_free(sim, /*free_devq*/TRUE);
21465942Sgibbs		sim = NULL;
21565942Sgibbs		goto fail;
21665942Sgibbs	}
21765942Sgibbs
21865942Sgibbs	xpt_setup_ccb(&csa.ccb_h, path, /*priority*/5);
21965942Sgibbs	csa.ccb_h.func_code = XPT_SASYNC_CB;
22065942Sgibbs	csa.event_enable = AC_LOST_DEVICE;
22165942Sgibbs	csa.callback = ahc_async;
22265942Sgibbs	csa.callback_arg = sim;
22365942Sgibbs	xpt_action((union ccb *)&csa);
22465942Sgibbs	count++;
22565942Sgibbs
22665942Sgibbs	if (ahc->features & AHC_TWIN) {
22765942Sgibbs		sim2 = cam_sim_alloc(ahc_action, ahc_poll, "ahc",
22866104Sgibbs				    ahc, device_get_unit(ahc->dev_softc), 1,
22971390Sgibbs				    AHC_MAX_QUEUE, devq);
23065942Sgibbs
23165942Sgibbs		if (sim2 == NULL) {
23265942Sgibbs			printf("ahc_attach: Unable to attach second "
23365942Sgibbs			       "bus due to resource shortage");
23465942Sgibbs			goto fail;
23565942Sgibbs		}
23665942Sgibbs
23765942Sgibbs		if (xpt_bus_register(sim2, bus_id2) != CAM_SUCCESS) {
23865942Sgibbs			printf("ahc_attach: Unable to attach second "
23965942Sgibbs			       "bus due to resource shortage");
24065942Sgibbs			/*
24165942Sgibbs			 * We do not want to destroy the device queue
24265942Sgibbs			 * because the first bus is using it.
24365942Sgibbs			 */
24465942Sgibbs			cam_sim_free(sim2, /*free_devq*/FALSE);
24565942Sgibbs			goto fail;
24665942Sgibbs		}
24765942Sgibbs
24865942Sgibbs		if (xpt_create_path(&path2, /*periph*/NULL,
24965942Sgibbs				    cam_sim_path(sim2),
25065942Sgibbs				    CAM_TARGET_WILDCARD,
25165942Sgibbs				    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
25265942Sgibbs			xpt_bus_deregister(cam_sim_path(sim2));
25365942Sgibbs			cam_sim_free(sim2, /*free_devq*/FALSE);
25465942Sgibbs			sim2 = NULL;
25565942Sgibbs			goto fail;
25665942Sgibbs		}
25765942Sgibbs		xpt_setup_ccb(&csa.ccb_h, path2, /*priority*/5);
25865942Sgibbs		csa.ccb_h.func_code = XPT_SASYNC_CB;
25965942Sgibbs		csa.event_enable = AC_LOST_DEVICE;
26065942Sgibbs		csa.callback = ahc_async;
26165942Sgibbs		csa.callback_arg = sim2;
26265942Sgibbs		xpt_action((union ccb *)&csa);
26365942Sgibbs		count++;
26465942Sgibbs	}
26565942Sgibbs
26665942Sgibbsfail:
26772552Sgibbs	if ((ahc->features & AHC_TWIN) != 0
26874094Sgibbs	 && (ahc->flags & AHC_PRIMARY_CHANNEL) != 0) {
26965942Sgibbs		ahc->platform_data->sim_b = sim;
27065942Sgibbs		ahc->platform_data->path_b = path;
27165942Sgibbs		ahc->platform_data->sim = sim2;
27265942Sgibbs		ahc->platform_data->path = path2;
27365942Sgibbs	} else {
27465942Sgibbs		ahc->platform_data->sim = sim;
27565942Sgibbs		ahc->platform_data->path = path;
27665942Sgibbs		ahc->platform_data->sim_b = sim2;
27765942Sgibbs		ahc->platform_data->path_b = path2;
27865942Sgibbs	}
27965942Sgibbs
280102674Sgibbs	if (count != 0) {
28165942Sgibbs		/* We have to wait until after any system dumps... */
28270204Sgibbs		ahc->platform_data->eh =
28370204Sgibbs		    EVENTHANDLER_REGISTER(shutdown_final, ahc_shutdown,
28470204Sgibbs					  ahc, SHUTDOWN_PRI_DEFAULT);
285102674Sgibbs		ahc_intr_enable(ahc, TRUE);
286102674Sgibbs	}
28765942Sgibbs
288102674Sgibbs	ahc_unlock(ahc, &s);
28965942Sgibbs	return (count);
29065942Sgibbs}
29165942Sgibbs
29265942Sgibbs/*
29365942Sgibbs * Catch an interrupt from the adapter
29465942Sgibbs */
29565942Sgibbsvoid
29670204Sgibbsahc_platform_intr(void *arg)
29765942Sgibbs{
29865942Sgibbs	struct	ahc_softc *ahc;
29965942Sgibbs
30065942Sgibbs	ahc = (struct ahc_softc *)arg;
30165942Sgibbs	ahc_intr(ahc);
30265942Sgibbs}
30365942Sgibbs
30465942Sgibbs/*
30565942Sgibbs * We have an scb which has been processed by the
30665942Sgibbs * adaptor, now we look to see how the operation
30765942Sgibbs * went.
30865942Sgibbs */
30965942Sgibbsvoid
31065942Sgibbsahc_done(struct ahc_softc *ahc, struct scb *scb)
31165942Sgibbs{
31265942Sgibbs	union ccb *ccb;
31365942Sgibbs
31465942Sgibbs	CAM_DEBUG(scb->io_ctx->ccb_h.path, CAM_DEBUG_TRACE,
31565942Sgibbs		  ("ahc_done - scb %d\n", scb->hscb->tag));
31665942Sgibbs
31765942Sgibbs	ccb = scb->io_ctx;
31865942Sgibbs	LIST_REMOVE(scb, pending_links);
319123579Sgibbs	if ((scb->flags & SCB_TIMEDOUT) != 0)
320123579Sgibbs		LIST_REMOVE(scb, timedout_links);
32166986Sgibbs	if ((scb->flags & SCB_UNTAGGEDQ) != 0) {
32265942Sgibbs		struct scb_tailq *untagged_q;
32372811Sgibbs		int target_offset;
32465942Sgibbs
32572811Sgibbs		target_offset = SCB_GET_TARGET_OFFSET(ahc, scb);
32672811Sgibbs		untagged_q = &ahc->untagged_queues[target_offset];
32765942Sgibbs		TAILQ_REMOVE(untagged_q, scb, links.tqe);
32866986Sgibbs		scb->flags &= ~SCB_UNTAGGEDQ;
32965942Sgibbs		ahc_run_untagged_queue(ahc, untagged_q);
33065942Sgibbs	}
33165942Sgibbs
332123579Sgibbs	untimeout(ahc_platform_timeout, (caddr_t)scb, ccb->ccb_h.timeout_ch);
33365942Sgibbs
33465942Sgibbs	if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
335115343Sscottl		bus_dmasync_op_t op;
33665942Sgibbs
33765942Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
33865942Sgibbs			op = BUS_DMASYNC_POSTREAD;
33965942Sgibbs		else
34065942Sgibbs			op = BUS_DMASYNC_POSTWRITE;
34165942Sgibbs		bus_dmamap_sync(ahc->buffer_dmat, scb->dmamap, op);
34265942Sgibbs		bus_dmamap_unload(ahc->buffer_dmat, scb->dmamap);
34365942Sgibbs	}
34465942Sgibbs
34565942Sgibbs	if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) {
34674972Sgibbs		struct cam_path *ccb_path;
34774972Sgibbs
34874972Sgibbs		/*
34974972Sgibbs		 * If we have finally disconnected, clean up our
35074972Sgibbs		 * pending device state.
35174972Sgibbs		 * XXX - There may be error states that cause where
35274972Sgibbs		 *       we will remain connected.
35374972Sgibbs		 */
35474972Sgibbs		ccb_path = ccb->ccb_h.path;
35574972Sgibbs		if (ahc->pending_device != NULL
35674972Sgibbs		 && xpt_path_comp(ahc->pending_device->path, ccb_path) == 0) {
35774972Sgibbs
35874972Sgibbs			if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
35974972Sgibbs				ahc->pending_device = NULL;
36074972Sgibbs			} else {
36195378Sgibbs				if (bootverbose) {
36295378Sgibbs					xpt_print_path(ccb->ccb_h.path);
36395378Sgibbs					printf("Still connected\n");
36495378Sgibbs				}
365123579Sgibbs				aic_freeze_ccb(ccb);
36674972Sgibbs			}
36774972Sgibbs		}
36874972Sgibbs
369123579Sgibbs		if (aic_get_transaction_status(scb) == CAM_REQ_INPROG)
37065942Sgibbs			ccb->ccb_h.status |= CAM_REQ_CMP;
37165942Sgibbs		ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
37265942Sgibbs		ahc_free_scb(ahc, scb);
37365942Sgibbs		xpt_done(ccb);
37465942Sgibbs		return;
37565942Sgibbs	}
37665942Sgibbs
37765942Sgibbs	/*
37865942Sgibbs	 * If the recovery SCB completes, we have to be
37965942Sgibbs	 * out of our timeout.
38065942Sgibbs	 */
38165942Sgibbs	if ((scb->flags & SCB_RECOVERY_SCB) != 0) {
38265942Sgibbs		struct	scb *list_scb;
38365942Sgibbs
384133911Sgibbs		ahc->scb_data->recovery_scbs--;
38565942Sgibbs
386123579Sgibbs		if (aic_get_transaction_status(scb) == CAM_BDR_SENT
387123579Sgibbs		 || aic_get_transaction_status(scb) == CAM_REQ_ABORTED)
388123579Sgibbs			aic_set_transaction_status(scb, CAM_CMD_TIMEOUT);
389133911Sgibbs
390133911Sgibbs		if (ahc->scb_data->recovery_scbs == 0) {
391133911Sgibbs			/*
392133911Sgibbs			 * All recovery actions have completed successfully,
393133911Sgibbs			 * so reinstate the timeouts for all other pending
394133911Sgibbs			 * commands.
395133911Sgibbs			 */
396133911Sgibbs			LIST_FOREACH(list_scb, &ahc->pending_scbs,
397133911Sgibbs				     pending_links) {
398133911Sgibbs
399150450Sgibbs				aic_scb_timer_reset(list_scb,
400150450Sgibbs						    aic_get_timeout(scb));
401133911Sgibbs			}
402133911Sgibbs
403133911Sgibbs			ahc_print_path(ahc, scb);
404133911Sgibbs			printf("no longer in timeout, status = %x\n",
405133911Sgibbs			       ccb->ccb_h.status);
406133911Sgibbs		}
40765942Sgibbs	}
40865942Sgibbs
40965942Sgibbs	/* Don't clobber any existing error state */
410123579Sgibbs	if (aic_get_transaction_status(scb) == CAM_REQ_INPROG) {
41165942Sgibbs		ccb->ccb_h.status |= CAM_REQ_CMP;
41265942Sgibbs	} else if ((scb->flags & SCB_SENSE) != 0) {
41365942Sgibbs		/*
41465942Sgibbs		 * We performed autosense retrieval.
41565942Sgibbs		 *
41665942Sgibbs		 * Zero any sense not transferred by the
41765942Sgibbs		 * device.  The SCSI spec mandates that any
41865942Sgibbs		 * untransfered data should be assumed to be
41965942Sgibbs		 * zero.  Complete the 'bounce' of sense information
42065942Sgibbs		 * through buffers accessible via bus-space by
42165942Sgibbs		 * copying it into the clients csio.
42265942Sgibbs		 */
42365942Sgibbs		memset(&ccb->csio.sense_data, 0, sizeof(ccb->csio.sense_data));
42465942Sgibbs		memcpy(&ccb->csio.sense_data,
42570807Sgibbs		       ahc_get_sense_buf(ahc, scb),
426123579Sgibbs		       (aic_le32toh(scb->sg_list->len) & AHC_SG_LEN_MASK)
42765942Sgibbs		       - ccb->csio.sense_resid);
42865942Sgibbs		scb->io_ctx->ccb_h.status |= CAM_AUTOSNS_VALID;
42965942Sgibbs	}
43065942Sgibbs	ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
43165942Sgibbs	ahc_free_scb(ahc, scb);
43265942Sgibbs	xpt_done(ccb);
43365942Sgibbs}
43465942Sgibbs
43565942Sgibbsstatic void
43665942Sgibbsahc_action(struct cam_sim *sim, union ccb *ccb)
43765942Sgibbs{
43865942Sgibbs	struct	ahc_softc *ahc;
43974972Sgibbs	struct	ahc_tmode_lstate *lstate;
44065942Sgibbs	u_int	target_id;
44165942Sgibbs	u_int	our_id;
44265942Sgibbs	long	s;
44365942Sgibbs
44465942Sgibbs	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahc_action\n"));
44565942Sgibbs
44665942Sgibbs	ahc = (struct ahc_softc *)cam_sim_softc(sim);
44765942Sgibbs
44865942Sgibbs	target_id = ccb->ccb_h.target_id;
44965942Sgibbs	our_id = SIM_SCSI_ID(ahc, sim);
45065942Sgibbs
45165942Sgibbs	switch (ccb->ccb_h.func_code) {
45265942Sgibbs	/* Common cases first */
45365942Sgibbs	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
45465942Sgibbs	case XPT_CONT_TARGET_IO:/* Continue Host Target I/O Connection*/
45565942Sgibbs	{
45674972Sgibbs		struct	   ahc_tmode_tstate *tstate;
45765942Sgibbs		cam_status status;
45865942Sgibbs
45965942Sgibbs		status = ahc_find_tmode_devs(ahc, sim, ccb, &tstate,
46065942Sgibbs					     &lstate, TRUE);
46165942Sgibbs
46265942Sgibbs		if (status != CAM_REQ_CMP) {
46365942Sgibbs			if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) {
46465942Sgibbs				/* Response from the black hole device */
46565942Sgibbs				tstate = NULL;
46665942Sgibbs				lstate = ahc->black_hole;
46765942Sgibbs			} else {
46865942Sgibbs				ccb->ccb_h.status = status;
46965942Sgibbs				xpt_done(ccb);
47065942Sgibbs				break;
47165942Sgibbs			}
47265942Sgibbs		}
47365942Sgibbs		if (ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO) {
47465942Sgibbs
47565942Sgibbs			ahc_lock(ahc, &s);
47665942Sgibbs			SLIST_INSERT_HEAD(&lstate->accept_tios, &ccb->ccb_h,
47765942Sgibbs					  sim_links.sle);
47865942Sgibbs			ccb->ccb_h.status = CAM_REQ_INPROG;
47965942Sgibbs			if ((ahc->flags & AHC_TQINFIFO_BLOCKED) != 0)
48065942Sgibbs				ahc_run_tqinfifo(ahc, /*paused*/FALSE);
48165942Sgibbs			ahc_unlock(ahc, &s);
48265942Sgibbs			break;
48365942Sgibbs		}
48465942Sgibbs
48565942Sgibbs		/*
48665942Sgibbs		 * The target_id represents the target we attempt to
48765942Sgibbs		 * select.  In target mode, this is the initiator of
48865942Sgibbs		 * the original command.
48965942Sgibbs		 */
49065942Sgibbs		our_id = target_id;
49165942Sgibbs		target_id = ccb->csio.init_id;
49265942Sgibbs		/* FALLTHROUGH */
49365942Sgibbs	}
49465942Sgibbs	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
49565942Sgibbs	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
49665942Sgibbs	{
49766717Sgibbs		struct	scb *scb;
49866717Sgibbs		struct	hardware_scb *hscb;
49965942Sgibbs
50068087Sgibbs		if ((ahc->flags & AHC_INITIATORROLE) == 0
50168087Sgibbs		 && (ccb->ccb_h.func_code == XPT_SCSI_IO
50268087Sgibbs		  || ccb->ccb_h.func_code == XPT_RESET_DEV)) {
50368087Sgibbs			ccb->ccb_h.status = CAM_PROVIDE_FAIL;
50468087Sgibbs			xpt_done(ccb);
50574972Sgibbs			return;
50668087Sgibbs		}
50768087Sgibbs
50865942Sgibbs		/*
50965942Sgibbs		 * get an scb to use.
51065942Sgibbs		 */
51166717Sgibbs		ahc_lock(ahc, &s);
51265942Sgibbs		if ((scb = ahc_get_scb(ahc)) == NULL) {
51365942Sgibbs
51466891Sgibbs			xpt_freeze_simq(sim, /*count*/1);
51565942Sgibbs			ahc->flags |= AHC_RESOURCE_SHORTAGE;
51665942Sgibbs			ahc_unlock(ahc, &s);
51766510Sgibbs			ccb->ccb_h.status = CAM_REQUEUE_REQ;
51865942Sgibbs			xpt_done(ccb);
51965942Sgibbs			return;
52065942Sgibbs		}
52166717Sgibbs		ahc_unlock(ahc, &s);
52265942Sgibbs
52365942Sgibbs		hscb = scb->hscb;
52465942Sgibbs
52565942Sgibbs		CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_SUBTRACE,
52665942Sgibbs			  ("start scb(%p)\n", scb));
52765942Sgibbs		scb->io_ctx = ccb;
52865942Sgibbs		/*
52965942Sgibbs		 * So we can find the SCB when an abort is requested
53065942Sgibbs		 */
53165942Sgibbs		ccb->ccb_h.ccb_scb_ptr = scb;
53265942Sgibbs
53365942Sgibbs		/*
53465942Sgibbs		 * Put all the arguments for the xfer in the scb
53565942Sgibbs		 */
53665942Sgibbs		hscb->control = 0;
53765942Sgibbs		hscb->scsiid = BUILD_SCSIID(ahc, sim, target_id, our_id);
53865942Sgibbs		hscb->lun = ccb->ccb_h.target_lun;
53965942Sgibbs		if (ccb->ccb_h.func_code == XPT_RESET_DEV) {
54065942Sgibbs			hscb->cdb_len = 0;
54165942Sgibbs			scb->flags |= SCB_DEVICE_RESET;
54265942Sgibbs			hscb->control |= MK_MESSAGE;
54365942Sgibbs			ahc_execute_scb(scb, NULL, 0, 0);
54465942Sgibbs		} else {
54565942Sgibbs			if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) {
54665942Sgibbs				struct target_data *tdata;
54765942Sgibbs
54865942Sgibbs				tdata = &hscb->shared_data.tdata;
54974972Sgibbs				if (ahc->pending_device == lstate)
55065942Sgibbs					scb->flags |= SCB_TARGET_IMMEDIATE;
55165942Sgibbs				hscb->control |= TARGET_SCB;
552107417Sscottl				scb->flags |= SCB_TARGET_SCB;
553107417Sscottl				tdata->target_phases = 0;
55465942Sgibbs				if ((ccb->ccb_h.flags & CAM_SEND_STATUS) != 0) {
55565942Sgibbs					tdata->target_phases |= SPHASE_PENDING;
55665942Sgibbs					tdata->scsi_status =
55765942Sgibbs					    ccb->csio.scsi_status;
55865942Sgibbs				}
55974972Sgibbs	 			if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT)
56074972Sgibbs					tdata->target_phases |= NO_DISCONNECT;
56174972Sgibbs
56265942Sgibbs				tdata->initiator_tag = ccb->csio.tag_id;
56365942Sgibbs			}
56465942Sgibbs			if (ccb->ccb_h.flags & CAM_TAG_ACTION_VALID)
56565942Sgibbs				hscb->control |= ccb->csio.tag_action;
56665942Sgibbs
56765942Sgibbs			ahc_setup_data(ahc, sim, &ccb->csio, scb);
56865942Sgibbs		}
56965942Sgibbs		break;
57065942Sgibbs	}
57165942Sgibbs	case XPT_NOTIFY_ACK:
57265942Sgibbs	case XPT_IMMED_NOTIFY:
57365942Sgibbs	{
57474972Sgibbs		struct	   ahc_tmode_tstate *tstate;
57574972Sgibbs		struct	   ahc_tmode_lstate *lstate;
57665942Sgibbs		cam_status status;
57765942Sgibbs
57865942Sgibbs		status = ahc_find_tmode_devs(ahc, sim, ccb, &tstate,
57965942Sgibbs					     &lstate, TRUE);
58065942Sgibbs
58165942Sgibbs		if (status != CAM_REQ_CMP) {
58265942Sgibbs			ccb->ccb_h.status = status;
58365942Sgibbs			xpt_done(ccb);
58465942Sgibbs			break;
58565942Sgibbs		}
58665942Sgibbs		SLIST_INSERT_HEAD(&lstate->immed_notifies, &ccb->ccb_h,
58765942Sgibbs				  sim_links.sle);
58865942Sgibbs		ccb->ccb_h.status = CAM_REQ_INPROG;
58965942Sgibbs		ahc_send_lstate_events(ahc, lstate);
59065942Sgibbs		break;
59165942Sgibbs	}
59265942Sgibbs	case XPT_EN_LUN:		/* Enable LUN as a target */
59365942Sgibbs		ahc_handle_en_lun(ahc, sim, ccb);
59465942Sgibbs		xpt_done(ccb);
59565942Sgibbs		break;
59665942Sgibbs	case XPT_ABORT:			/* Abort the specified CCB */
59765942Sgibbs	{
59865942Sgibbs		ahc_abort_ccb(ahc, sim, ccb);
59965942Sgibbs		break;
60065942Sgibbs	}
60165942Sgibbs	case XPT_SET_TRAN_SETTINGS:
60265942Sgibbs	{
60365942Sgibbs#ifdef AHC_NEW_TRAN_SETTINGS
60465942Sgibbs		struct	ahc_devinfo devinfo;
60565942Sgibbs		struct	ccb_trans_settings *cts;
60665942Sgibbs		struct	ccb_trans_settings_scsi *scsi;
60765942Sgibbs		struct	ccb_trans_settings_spi *spi;
60865942Sgibbs		struct	ahc_initiator_tinfo *tinfo;
60974972Sgibbs		struct	ahc_tmode_tstate *tstate;
61065942Sgibbs		uint16_t *discenable;
61165942Sgibbs		uint16_t *tagenable;
61265942Sgibbs		u_int	update_type;
61365942Sgibbs
61465942Sgibbs		cts = &ccb->cts;
61565942Sgibbs		scsi = &cts->proto_specific.scsi;
61665942Sgibbs		spi = &cts->xport_specific.spi;
61765942Sgibbs		ahc_compile_devinfo(&devinfo, SIM_SCSI_ID(ahc, sim),
61865942Sgibbs				    cts->ccb_h.target_id,
61965942Sgibbs				    cts->ccb_h.target_lun,
62065942Sgibbs				    SIM_CHANNEL(ahc, sim),
62165942Sgibbs				    ROLE_UNKNOWN);
62265942Sgibbs		tinfo = ahc_fetch_transinfo(ahc, devinfo.channel,
62365942Sgibbs					    devinfo.our_scsiid,
62465942Sgibbs					    devinfo.target, &tstate);
62565942Sgibbs		update_type = 0;
62665942Sgibbs		if (cts->type == CTS_TYPE_CURRENT_SETTINGS) {
62765942Sgibbs			update_type |= AHC_TRANS_GOAL;
62865942Sgibbs			discenable = &tstate->discenable;
62965942Sgibbs			tagenable = &tstate->tagenable;
63076634Sgibbs			tinfo->curr.protocol_version =
63165942Sgibbs			    cts->protocol_version;
63276634Sgibbs			tinfo->curr.transport_version =
63365942Sgibbs			    cts->transport_version;
63465942Sgibbs			tinfo->goal.protocol_version =
63565942Sgibbs			    cts->protocol_version;
63665942Sgibbs			tinfo->goal.transport_version =
63765942Sgibbs			    cts->transport_version;
63865942Sgibbs		} else if (cts->type == CTS_TYPE_USER_SETTINGS) {
63965942Sgibbs			update_type |= AHC_TRANS_USER;
64065942Sgibbs			discenable = &ahc->user_discenable;
64165942Sgibbs			tagenable = &ahc->user_tagenable;
64265942Sgibbs			tinfo->user.protocol_version =
64365942Sgibbs			    cts->protocol_version;
64465942Sgibbs			tinfo->user.transport_version =
64565942Sgibbs			    cts->transport_version;
64665942Sgibbs		} else {
64765942Sgibbs			ccb->ccb_h.status = CAM_REQ_INVALID;
64865942Sgibbs			xpt_done(ccb);
64965942Sgibbs			break;
65065942Sgibbs		}
65165942Sgibbs
65265942Sgibbs		ahc_lock(ahc, &s);
65365942Sgibbs
65465942Sgibbs		if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
65565942Sgibbs			if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0)
65665942Sgibbs				*discenable |= devinfo.target_mask;
65765942Sgibbs			else
65865942Sgibbs				*discenable &= ~devinfo.target_mask;
65965942Sgibbs		}
66065942Sgibbs
66165942Sgibbs		if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
66265942Sgibbs			if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0)
66365942Sgibbs				*tagenable |= devinfo.target_mask;
66465942Sgibbs			else
66565942Sgibbs				*tagenable &= ~devinfo.target_mask;
66665942Sgibbs		}
66765942Sgibbs
66865942Sgibbs		if ((spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) {
66968087Sgibbs			ahc_validate_width(ahc, /*tinfo limit*/NULL,
67068087Sgibbs					   &spi->bus_width, ROLE_UNKNOWN);
67165942Sgibbs			ahc_set_width(ahc, &devinfo, spi->bus_width,
67265942Sgibbs				      update_type, /*paused*/FALSE);
67365942Sgibbs		}
67465942Sgibbs
67565942Sgibbs		if ((spi->valid & CTS_SPI_VALID_PPR_OPTIONS) == 0) {
67665942Sgibbs			if (update_type == AHC_TRANS_USER)
67765942Sgibbs				spi->ppr_options = tinfo->user.ppr_options;
67865942Sgibbs			else
67965942Sgibbs				spi->ppr_options = tinfo->goal.ppr_options;
68065942Sgibbs		}
68165942Sgibbs
68265942Sgibbs		if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0) {
68365942Sgibbs			if (update_type == AHC_TRANS_USER)
68465942Sgibbs				spi->sync_offset = tinfo->user.offset;
68565942Sgibbs			else
68665942Sgibbs				spi->sync_offset = tinfo->goal.offset;
68765942Sgibbs		}
68865942Sgibbs
68965942Sgibbs		if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0) {
69065942Sgibbs			if (update_type == AHC_TRANS_USER)
69165942Sgibbs				spi->sync_period = tinfo->user.period;
69265942Sgibbs			else
69365942Sgibbs				spi->sync_period = tinfo->goal.period;
69465942Sgibbs		}
69565942Sgibbs
69665942Sgibbs		if (((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0)
69765942Sgibbs		 || ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)) {
69865942Sgibbs			struct ahc_syncrate *syncrate;
69965942Sgibbs			u_int maxsync;
70065942Sgibbs
70165942Sgibbs			if ((ahc->features & AHC_ULTRA2) != 0)
70265942Sgibbs				maxsync = AHC_SYNCRATE_DT;
70365942Sgibbs			else if ((ahc->features & AHC_ULTRA) != 0)
70465942Sgibbs				maxsync = AHC_SYNCRATE_ULTRA;
70565942Sgibbs			else
70665942Sgibbs				maxsync = AHC_SYNCRATE_FAST;
70765942Sgibbs
70895378Sgibbs			if (spi->bus_width != MSG_EXT_WDTR_BUS_16_BIT)
70995378Sgibbs				spi->ppr_options &= ~MSG_EXT_PPR_DT_REQ;
71095378Sgibbs
71165942Sgibbs			syncrate = ahc_find_syncrate(ahc, &spi->sync_period,
71265942Sgibbs						     &spi->ppr_options,
71365942Sgibbs						     maxsync);
71468087Sgibbs			ahc_validate_offset(ahc, /*tinfo limit*/NULL,
71568087Sgibbs					    syncrate, &spi->sync_offset,
71668087Sgibbs					    spi->bus_width, ROLE_UNKNOWN);
71765942Sgibbs
71865942Sgibbs			/* We use a period of 0 to represent async */
71965942Sgibbs			if (spi->sync_offset == 0) {
72065942Sgibbs				spi->sync_period = 0;
72165942Sgibbs				spi->ppr_options = 0;
72265942Sgibbs			}
72365942Sgibbs
72465942Sgibbs			ahc_set_syncrate(ahc, &devinfo, syncrate,
72565942Sgibbs					 spi->sync_period, spi->sync_offset,
72665942Sgibbs					 spi->ppr_options, update_type,
72765942Sgibbs					 /*paused*/FALSE);
72865942Sgibbs		}
72965942Sgibbs		ahc_unlock(ahc, &s);
73065942Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
73165942Sgibbs		xpt_done(ccb);
73265942Sgibbs#else
73365942Sgibbs		struct	  ahc_devinfo devinfo;
73465942Sgibbs		struct	  ccb_trans_settings *cts;
73565942Sgibbs		struct	  ahc_initiator_tinfo *tinfo;
73674972Sgibbs		struct	  ahc_tmode_tstate *tstate;
73765942Sgibbs		uint16_t *discenable;
73865942Sgibbs		uint16_t *tagenable;
73965942Sgibbs		u_int	  update_type;
74065942Sgibbs		long	  s;
74165942Sgibbs
74265942Sgibbs		cts = &ccb->cts;
74365942Sgibbs		ahc_compile_devinfo(&devinfo, SIM_SCSI_ID(ahc, sim),
74465942Sgibbs				    cts->ccb_h.target_id,
74565942Sgibbs				    cts->ccb_h.target_lun,
74665942Sgibbs				    SIM_CHANNEL(ahc, sim),
74765942Sgibbs				    ROLE_UNKNOWN);
74865942Sgibbs		tinfo = ahc_fetch_transinfo(ahc, devinfo.channel,
74965942Sgibbs					    devinfo.our_scsiid,
75065942Sgibbs					    devinfo.target, &tstate);
75165942Sgibbs		update_type = 0;
75265942Sgibbs		if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) {
75365942Sgibbs			update_type |= AHC_TRANS_GOAL;
75465942Sgibbs			discenable = &tstate->discenable;
75565942Sgibbs			tagenable = &tstate->tagenable;
75665942Sgibbs		} else if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) {
75765942Sgibbs			update_type |= AHC_TRANS_USER;
75865942Sgibbs			discenable = &ahc->user_discenable;
75965942Sgibbs			tagenable = &ahc->user_tagenable;
76065942Sgibbs		} else {
76165942Sgibbs			ccb->ccb_h.status = CAM_REQ_INVALID;
76265942Sgibbs			xpt_done(ccb);
76365942Sgibbs			break;
76465942Sgibbs		}
76565942Sgibbs
76665942Sgibbs		ahc_lock(ahc, &s);
76765942Sgibbs
76865942Sgibbs		if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) {
76965942Sgibbs			if ((cts->flags & CCB_TRANS_DISC_ENB) != 0)
77065942Sgibbs				*discenable |= devinfo.target_mask;
77165942Sgibbs			else
77265942Sgibbs				*discenable &= ~devinfo.target_mask;
77365942Sgibbs		}
77465942Sgibbs
77565942Sgibbs		if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) {
77665942Sgibbs			if ((cts->flags & CCB_TRANS_TAG_ENB) != 0)
77765942Sgibbs				*tagenable |= devinfo.target_mask;
77865942Sgibbs			else
77965942Sgibbs				*tagenable &= ~devinfo.target_mask;
78065942Sgibbs		}
78165942Sgibbs
78265942Sgibbs		if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) {
78368087Sgibbs			ahc_validate_width(ahc, /*tinfo limit*/NULL,
78468087Sgibbs					   &cts->bus_width, ROLE_UNKNOWN);
78565942Sgibbs			ahc_set_width(ahc, &devinfo, cts->bus_width,
78665942Sgibbs				      update_type, /*paused*/FALSE);
78765942Sgibbs		}
78865942Sgibbs
78965942Sgibbs		if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) == 0) {
79065942Sgibbs			if (update_type == AHC_TRANS_USER)
79165942Sgibbs				cts->sync_offset = tinfo->user.offset;
79265942Sgibbs			else
79365942Sgibbs				cts->sync_offset = tinfo->goal.offset;
79465942Sgibbs		}
79565942Sgibbs
79665942Sgibbs		if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) == 0) {
79765942Sgibbs			if (update_type == AHC_TRANS_USER)
79865942Sgibbs				cts->sync_period = tinfo->user.period;
79965942Sgibbs			else
80065942Sgibbs				cts->sync_period = tinfo->goal.period;
80165942Sgibbs		}
80265942Sgibbs
80365942Sgibbs		if (((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0)
80465942Sgibbs		 || ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)) {
80565942Sgibbs			struct ahc_syncrate *syncrate;
80665942Sgibbs			u_int ppr_options;
80765942Sgibbs			u_int maxsync;
80865942Sgibbs
80965942Sgibbs			if ((ahc->features & AHC_ULTRA2) != 0)
81065942Sgibbs				maxsync = AHC_SYNCRATE_DT;
81165942Sgibbs			else if ((ahc->features & AHC_ULTRA) != 0)
81265942Sgibbs				maxsync = AHC_SYNCRATE_ULTRA;
81365942Sgibbs			else
81465942Sgibbs				maxsync = AHC_SYNCRATE_FAST;
81565942Sgibbs
81665942Sgibbs			ppr_options = 0;
81795378Sgibbs			if (cts->sync_period <= 9
81895378Sgibbs			 && cts->bus_width == MSG_EXT_WDTR_BUS_16_BIT)
81965942Sgibbs				ppr_options = MSG_EXT_PPR_DT_REQ;
82065942Sgibbs
82165942Sgibbs			syncrate = ahc_find_syncrate(ahc, &cts->sync_period,
82265942Sgibbs						     &ppr_options,
82365942Sgibbs						     maxsync);
82468087Sgibbs			ahc_validate_offset(ahc, /*tinfo limit*/NULL,
82568087Sgibbs					    syncrate, &cts->sync_offset,
82668087Sgibbs					    MSG_EXT_WDTR_BUS_8_BIT,
82768087Sgibbs					    ROLE_UNKNOWN);
82865942Sgibbs
82965942Sgibbs			/* We use a period of 0 to represent async */
83065942Sgibbs			if (cts->sync_offset == 0) {
83165942Sgibbs				cts->sync_period = 0;
83265942Sgibbs				ppr_options = 0;
83365942Sgibbs			}
83465942Sgibbs
83565942Sgibbs			if (ppr_options == MSG_EXT_PPR_DT_REQ
83665942Sgibbs			 && tinfo->user.transport_version >= 3) {
83765942Sgibbs				tinfo->goal.transport_version =
83865942Sgibbs				    tinfo->user.transport_version;
83976634Sgibbs				tinfo->curr.transport_version =
84065942Sgibbs				    tinfo->user.transport_version;
84165942Sgibbs			}
84265942Sgibbs
84365942Sgibbs			ahc_set_syncrate(ahc, &devinfo, syncrate,
84465942Sgibbs					 cts->sync_period, cts->sync_offset,
84565942Sgibbs					 ppr_options, update_type,
84665942Sgibbs					 /*paused*/FALSE);
84765942Sgibbs		}
84865942Sgibbs		ahc_unlock(ahc, &s);
84965942Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
85065942Sgibbs		xpt_done(ccb);
85165942Sgibbs#endif
85265942Sgibbs		break;
85365942Sgibbs	}
85465942Sgibbs	case XPT_GET_TRAN_SETTINGS:
85565942Sgibbs	/* Get default/user set transfer settings for the target */
85665942Sgibbs	{
85765942Sgibbs
85865942Sgibbs		ahc_lock(ahc, &s);
85965942Sgibbs		ahc_get_tran_settings(ahc, SIM_SCSI_ID(ahc, sim),
86065942Sgibbs				      SIM_CHANNEL(ahc, sim), &ccb->cts);
86165942Sgibbs		ahc_unlock(ahc, &s);
86265942Sgibbs		xpt_done(ccb);
86365942Sgibbs		break;
86465942Sgibbs	}
86565942Sgibbs	case XPT_CALC_GEOMETRY:
86665942Sgibbs	{
867123579Sgibbs		int extended;
86865942Sgibbs
86965942Sgibbs		extended = SIM_IS_SCSIBUS_B(ahc, sim)
870123579Sgibbs			 ? ahc->flags & AHC_EXTENDED_TRANS_B
871123579Sgibbs			 : ahc->flags & AHC_EXTENDED_TRANS_A;
872123579Sgibbs		aic_calc_geometry(&ccb->ccg, extended);
87365942Sgibbs		xpt_done(ccb);
87465942Sgibbs		break;
87565942Sgibbs	}
87665942Sgibbs	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
87765942Sgibbs	{
87865942Sgibbs		int  found;
87965942Sgibbs
88065942Sgibbs		ahc_lock(ahc, &s);
88165942Sgibbs		found = ahc_reset_channel(ahc, SIM_CHANNEL(ahc, sim),
88265942Sgibbs					  /*initiate reset*/TRUE);
88365942Sgibbs		ahc_unlock(ahc, &s);
88465942Sgibbs		if (bootverbose) {
88565942Sgibbs			xpt_print_path(SIM_PATH(ahc, sim));
88665942Sgibbs			printf("SCSI bus reset delivered. "
88765942Sgibbs			       "%d SCBs aborted.\n", found);
88865942Sgibbs		}
88965942Sgibbs		ccb->ccb_h.status = CAM_REQ_CMP;
89065942Sgibbs		xpt_done(ccb);
89165942Sgibbs		break;
89265942Sgibbs	}
89365942Sgibbs	case XPT_TERM_IO:		/* Terminate the I/O process */
89465942Sgibbs		/* XXX Implement */
89565942Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
89665942Sgibbs		xpt_done(ccb);
89765942Sgibbs		break;
89865942Sgibbs	case XPT_PATH_INQ:		/* Path routing inquiry */
89965942Sgibbs	{
90065942Sgibbs		struct ccb_pathinq *cpi = &ccb->cpi;
90165942Sgibbs
90265942Sgibbs		cpi->version_num = 1; /* XXX??? */
90365942Sgibbs		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE;
90465942Sgibbs		if ((ahc->features & AHC_WIDE) != 0)
90565942Sgibbs			cpi->hba_inquiry |= PI_WIDE_16;
90668087Sgibbs		if ((ahc->features & AHC_TARGETMODE) != 0) {
90765942Sgibbs			cpi->target_sprt = PIT_PROCESSOR
90865942Sgibbs					 | PIT_DISCONNECT
90965942Sgibbs					 | PIT_TERM_IO;
91065942Sgibbs		} else {
91165942Sgibbs			cpi->target_sprt = 0;
91265942Sgibbs		}
91368087Sgibbs		cpi->hba_misc = 0;
91465942Sgibbs		cpi->hba_eng_cnt = 0;
91565942Sgibbs		cpi->max_target = (ahc->features & AHC_WIDE) ? 15 : 7;
91670204Sgibbs		cpi->max_lun = AHC_NUM_LUNS - 1;
91765942Sgibbs		if (SIM_IS_SCSIBUS_B(ahc, sim)) {
91865942Sgibbs			cpi->initiator_id = ahc->our_id_b;
91965942Sgibbs			if ((ahc->flags & AHC_RESET_BUS_B) == 0)
92065942Sgibbs				cpi->hba_misc |= PIM_NOBUSRESET;
92165942Sgibbs		} else {
92265942Sgibbs			cpi->initiator_id = ahc->our_id;
92365942Sgibbs			if ((ahc->flags & AHC_RESET_BUS_A) == 0)
92465942Sgibbs				cpi->hba_misc |= PIM_NOBUSRESET;
92565942Sgibbs		}
92665942Sgibbs		cpi->bus_id = cam_sim_bus(sim);
92765942Sgibbs		cpi->base_transfer_speed = 3300;
92865942Sgibbs		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
92965942Sgibbs		strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN);
93065942Sgibbs		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
93165942Sgibbs		cpi->unit_number = cam_sim_unit(sim);
93265942Sgibbs#ifdef AHC_NEW_TRAN_SETTINGS
93365942Sgibbs		cpi->protocol = PROTO_SCSI;
93465942Sgibbs		cpi->protocol_version = SCSI_REV_2;
93565942Sgibbs		cpi->transport = XPORT_SPI;
93665942Sgibbs		cpi->transport_version = 2;
93765942Sgibbs		cpi->xport_specific.spi.ppr_options = SID_SPI_CLOCK_ST;
93865942Sgibbs		if ((ahc->features & AHC_DT) != 0) {
93965942Sgibbs			cpi->transport_version = 3;
94065942Sgibbs			cpi->xport_specific.spi.ppr_options =
94165942Sgibbs			    SID_SPI_CLOCK_DT_ST;
94265942Sgibbs		}
94365942Sgibbs#endif
94465942Sgibbs		cpi->ccb_h.status = CAM_REQ_CMP;
94565942Sgibbs		xpt_done(ccb);
94665942Sgibbs		break;
94765942Sgibbs	}
94865942Sgibbs	default:
94968087Sgibbs		ccb->ccb_h.status = CAM_PROVIDE_FAIL;
95065942Sgibbs		xpt_done(ccb);
95165942Sgibbs		break;
95265942Sgibbs	}
95365942Sgibbs}
95465942Sgibbs
95565942Sgibbsstatic void
95665942Sgibbsahc_get_tran_settings(struct ahc_softc *ahc, int our_id, char channel,
95765942Sgibbs		      struct ccb_trans_settings *cts)
95865942Sgibbs{
95965942Sgibbs#ifdef AHC_NEW_TRAN_SETTINGS
96065942Sgibbs	struct	ahc_devinfo devinfo;
96165942Sgibbs	struct	ccb_trans_settings_scsi *scsi;
96265942Sgibbs	struct	ccb_trans_settings_spi *spi;
96365942Sgibbs	struct	ahc_initiator_tinfo *targ_info;
96474972Sgibbs	struct	ahc_tmode_tstate *tstate;
96565942Sgibbs	struct	ahc_transinfo *tinfo;
96665942Sgibbs
96765942Sgibbs	scsi = &cts->proto_specific.scsi;
96865942Sgibbs	spi = &cts->xport_specific.spi;
96965942Sgibbs	ahc_compile_devinfo(&devinfo, our_id,
97065942Sgibbs			    cts->ccb_h.target_id,
97165942Sgibbs			    cts->ccb_h.target_lun,
97265942Sgibbs			    channel, ROLE_UNKNOWN);
97365942Sgibbs	targ_info = ahc_fetch_transinfo(ahc, devinfo.channel,
97465942Sgibbs					devinfo.our_scsiid,
97565942Sgibbs					devinfo.target, &tstate);
97665942Sgibbs
97765942Sgibbs	if (cts->type == CTS_TYPE_CURRENT_SETTINGS)
97876634Sgibbs		tinfo = &targ_info->curr;
97965942Sgibbs	else
98065942Sgibbs		tinfo = &targ_info->user;
98165942Sgibbs
98265942Sgibbs	scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
98365942Sgibbs	spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
98465942Sgibbs	if (cts->type == CTS_TYPE_USER_SETTINGS) {
98565942Sgibbs		if ((ahc->user_discenable & devinfo.target_mask) != 0)
98665942Sgibbs			spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
98765942Sgibbs
98865942Sgibbs		if ((ahc->user_tagenable & devinfo.target_mask) != 0)
98965942Sgibbs			scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
99065942Sgibbs	} else {
99165942Sgibbs		if ((tstate->discenable & devinfo.target_mask) != 0)
99265942Sgibbs			spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
99365942Sgibbs
99465942Sgibbs		if ((tstate->tagenable & devinfo.target_mask) != 0)
99565942Sgibbs			scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
99665942Sgibbs	}
99765942Sgibbs	cts->protocol_version = tinfo->protocol_version;
99865942Sgibbs	cts->transport_version = tinfo->transport_version;
99965942Sgibbs
100065942Sgibbs	spi->sync_period = tinfo->period;
100165942Sgibbs	spi->sync_offset = tinfo->offset;
100265942Sgibbs	spi->bus_width = tinfo->width;
100365942Sgibbs	spi->ppr_options = tinfo->ppr_options;
100465942Sgibbs
100565942Sgibbs	cts->protocol = PROTO_SCSI;
100665942Sgibbs	cts->transport = XPORT_SPI;
100765942Sgibbs	spi->valid = CTS_SPI_VALID_SYNC_RATE
100865942Sgibbs		   | CTS_SPI_VALID_SYNC_OFFSET
100965942Sgibbs		   | CTS_SPI_VALID_BUS_WIDTH
101065942Sgibbs		   | CTS_SPI_VALID_PPR_OPTIONS;
101165942Sgibbs
101266717Sgibbs	if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD) {
101366717Sgibbs		scsi->valid = CTS_SCSI_VALID_TQ;
101466717Sgibbs		spi->valid |= CTS_SPI_VALID_DISC;
101566717Sgibbs	} else {
101666717Sgibbs		scsi->valid = 0;
101766717Sgibbs	}
101866717Sgibbs
101965942Sgibbs	cts->ccb_h.status = CAM_REQ_CMP;
102065942Sgibbs#else
102165942Sgibbs	struct	ahc_devinfo devinfo;
102265942Sgibbs	struct	ahc_initiator_tinfo *targ_info;
102374972Sgibbs	struct	ahc_tmode_tstate *tstate;
102465942Sgibbs	struct	ahc_transinfo *tinfo;
102565942Sgibbs
102665942Sgibbs	ahc_compile_devinfo(&devinfo, our_id,
102765942Sgibbs			    cts->ccb_h.target_id,
102865942Sgibbs			    cts->ccb_h.target_lun,
102965942Sgibbs			    channel, ROLE_UNKNOWN);
103065942Sgibbs	targ_info = ahc_fetch_transinfo(ahc, devinfo.channel,
103165942Sgibbs					devinfo.our_scsiid,
103265942Sgibbs					devinfo.target, &tstate);
103365942Sgibbs
103465942Sgibbs	if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0)
103576634Sgibbs		tinfo = &targ_info->curr;
103665942Sgibbs	else
103765942Sgibbs		tinfo = &targ_info->user;
103865942Sgibbs
103965942Sgibbs	cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB);
104066760Sgibbs	if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) == 0) {
104165942Sgibbs		if ((ahc->user_discenable & devinfo.target_mask) != 0)
104265942Sgibbs			cts->flags |= CCB_TRANS_DISC_ENB;
104365942Sgibbs
104465942Sgibbs		if ((ahc->user_tagenable & devinfo.target_mask) != 0)
104565942Sgibbs			cts->flags |= CCB_TRANS_TAG_ENB;
104665942Sgibbs	} else {
104765942Sgibbs		if ((tstate->discenable & devinfo.target_mask) != 0)
104865942Sgibbs			cts->flags |= CCB_TRANS_DISC_ENB;
104965942Sgibbs
105065942Sgibbs		if ((tstate->tagenable & devinfo.target_mask) != 0)
105165942Sgibbs			cts->flags |= CCB_TRANS_TAG_ENB;
105265942Sgibbs	}
105365942Sgibbs	cts->sync_period = tinfo->period;
105465942Sgibbs	cts->sync_offset = tinfo->offset;
105565942Sgibbs	cts->bus_width = tinfo->width;
105665942Sgibbs
105765942Sgibbs	cts->valid = CCB_TRANS_SYNC_RATE_VALID
105865942Sgibbs		   | CCB_TRANS_SYNC_OFFSET_VALID
105966717Sgibbs		   | CCB_TRANS_BUS_WIDTH_VALID;
106065942Sgibbs
106166717Sgibbs	if (cts->ccb_h.target_lun != CAM_LUN_WILDCARD)
106266717Sgibbs		cts->valid |= CCB_TRANS_DISC_VALID|CCB_TRANS_TQ_VALID;
106366717Sgibbs
106465942Sgibbs	cts->ccb_h.status = CAM_REQ_CMP;
106565942Sgibbs#endif
106665942Sgibbs}
106765942Sgibbs
106865942Sgibbsstatic void
106965942Sgibbsahc_async(void *callback_arg, uint32_t code, struct cam_path *path, void *arg)
107065942Sgibbs{
107165942Sgibbs	struct ahc_softc *ahc;
107265942Sgibbs	struct cam_sim *sim;
107365942Sgibbs
107465942Sgibbs	sim = (struct cam_sim *)callback_arg;
107565942Sgibbs	ahc = (struct ahc_softc *)cam_sim_softc(sim);
107665942Sgibbs	switch (code) {
107765942Sgibbs	case AC_LOST_DEVICE:
107865942Sgibbs	{
107965942Sgibbs		struct	ahc_devinfo devinfo;
108065942Sgibbs		long	s;
108165942Sgibbs
108265942Sgibbs		ahc_compile_devinfo(&devinfo, SIM_SCSI_ID(ahc, sim),
108365942Sgibbs				    xpt_path_target_id(path),
108465942Sgibbs				    xpt_path_lun_id(path),
108565942Sgibbs				    SIM_CHANNEL(ahc, sim),
108665942Sgibbs				    ROLE_UNKNOWN);
108765942Sgibbs
108865942Sgibbs		/*
108965942Sgibbs		 * Revert to async/narrow transfers
109065942Sgibbs		 * for the next device.
109165942Sgibbs		 */
109265942Sgibbs		ahc_lock(ahc, &s);
109365942Sgibbs		ahc_set_width(ahc, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
109465942Sgibbs			      AHC_TRANS_GOAL|AHC_TRANS_CUR, /*paused*/FALSE);
109565942Sgibbs		ahc_set_syncrate(ahc, &devinfo, /*syncrate*/NULL,
109665942Sgibbs				 /*period*/0, /*offset*/0, /*ppr_options*/0,
109765942Sgibbs				 AHC_TRANS_GOAL|AHC_TRANS_CUR,
109865942Sgibbs				 /*paused*/FALSE);
109965942Sgibbs		ahc_unlock(ahc, &s);
110065942Sgibbs		break;
110165942Sgibbs	}
110265942Sgibbs	default:
110365942Sgibbs		break;
110465942Sgibbs	}
110565942Sgibbs}
110665942Sgibbs
110765942Sgibbsstatic void
110865942Sgibbsahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments,
110965942Sgibbs		int error)
111065942Sgibbs{
111166717Sgibbs	struct	scb *scb;
111266717Sgibbs	union	ccb *ccb;
111366717Sgibbs	struct	ahc_softc *ahc;
111466717Sgibbs	struct	ahc_initiator_tinfo *tinfo;
111574972Sgibbs	struct	ahc_tmode_tstate *tstate;
111666717Sgibbs	u_int	mask;
111766717Sgibbs	long	s;
111865942Sgibbs
111965942Sgibbs	scb = (struct scb *)arg;
112065942Sgibbs	ccb = scb->io_ctx;
112166986Sgibbs	ahc = scb->ahc_softc;
112265942Sgibbs
112365942Sgibbs	if (error != 0) {
112465942Sgibbs		if (error == EFBIG)
1125123579Sgibbs			aic_set_transaction_status(scb, CAM_REQ_TOO_BIG);
112665942Sgibbs		else
1127123579Sgibbs			aic_set_transaction_status(scb, CAM_REQ_CMP_ERR);
112865942Sgibbs		if (nsegments != 0)
112965942Sgibbs			bus_dmamap_unload(ahc->buffer_dmat, scb->dmamap);
113066647Sgibbs		ahc_lock(ahc, &s);
113165942Sgibbs		ahc_free_scb(ahc, scb);
113266647Sgibbs		ahc_unlock(ahc, &s);
113365942Sgibbs		xpt_done(ccb);
113465942Sgibbs		return;
113565942Sgibbs	}
113665942Sgibbs	if (nsegments != 0) {
113765942Sgibbs		struct	  ahc_dma_seg *sg;
113865942Sgibbs		bus_dma_segment_t *end_seg;
1139115343Sscottl		bus_dmasync_op_t op;
114065942Sgibbs
114165942Sgibbs		end_seg = dm_segs + nsegments;
114265942Sgibbs
114365942Sgibbs		/* Copy the segments into our SG list */
114465942Sgibbs		sg = scb->sg_list;
114565942Sgibbs		while (dm_segs < end_seg) {
114679874Sgibbs			uint32_t len;
114779874Sgibbs
1148123579Sgibbs			sg->addr = aic_htole32(dm_segs->ds_addr);
114979874Sgibbs			len = dm_segs->ds_len
115079874Sgibbs			    | ((dm_segs->ds_addr >> 8) & 0x7F000000);
1151123579Sgibbs			sg->len = aic_htole32(len);
115265942Sgibbs			sg++;
115365942Sgibbs			dm_segs++;
115465942Sgibbs		}
115565942Sgibbs
115665942Sgibbs		/*
115765942Sgibbs		 * Note where to find the SG entries in bus space.
115865942Sgibbs		 * We also set the full residual flag which the
115965942Sgibbs		 * sequencer will clear as soon as a data transfer
116065942Sgibbs		 * occurs.
116165942Sgibbs		 */
1162123579Sgibbs		scb->hscb->sgptr = aic_htole32(scb->sg_list_phys|SG_FULL_RESID);
116365942Sgibbs
116465942Sgibbs		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
116565942Sgibbs			op = BUS_DMASYNC_PREREAD;
116665942Sgibbs		else
116765942Sgibbs			op = BUS_DMASYNC_PREWRITE;
116865942Sgibbs
116965942Sgibbs		bus_dmamap_sync(ahc->buffer_dmat, scb->dmamap, op);
117065942Sgibbs
117165942Sgibbs		if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) {
117265942Sgibbs			struct target_data *tdata;
117365942Sgibbs
117465942Sgibbs			tdata = &scb->hscb->shared_data.tdata;
117565942Sgibbs			tdata->target_phases |= DPHASE_PENDING;
1176123579Sgibbs			/*
1177123579Sgibbs			 * CAM data direction is relative to the initiator.
1178123579Sgibbs			 */
117965942Sgibbs			if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
118065942Sgibbs				tdata->data_phase = P_DATAOUT;
118165942Sgibbs			else
118265942Sgibbs				tdata->data_phase = P_DATAIN;
118365942Sgibbs
118465942Sgibbs			/*
118565942Sgibbs			 * If the transfer is of an odd length and in the
118665942Sgibbs			 * "in" direction (scsi->HostBus), then it may
118765942Sgibbs			 * trigger a bug in the 'WideODD' feature of
118865942Sgibbs			 * non-Ultra2 chips.  Force the total data-length
118965942Sgibbs			 * to be even by adding an extra, 1 byte, SG,
119065942Sgibbs			 * element.  We do this even if we are not currently
119165942Sgibbs			 * negotiated wide as negotiation could occur before
119265942Sgibbs			 * this command is executed.
119365942Sgibbs			 */
119465942Sgibbs			if ((ahc->bugs & AHC_TMODE_WIDEODD_BUG) != 0
119565942Sgibbs			 && (ccb->csio.dxfer_len & 0x1) != 0
1196123579Sgibbs			 && (ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) {
119765942Sgibbs
119865942Sgibbs				nsegments++;
119965942Sgibbs				if (nsegments > AHC_NSEG) {
120065942Sgibbs
1201123579Sgibbs					aic_set_transaction_status(scb,
120265942Sgibbs					    CAM_REQ_TOO_BIG);
120365942Sgibbs					bus_dmamap_unload(ahc->buffer_dmat,
120465942Sgibbs							  scb->dmamap);
120566647Sgibbs					ahc_lock(ahc, &s);
120665942Sgibbs					ahc_free_scb(ahc, scb);
120766647Sgibbs					ahc_unlock(ahc, &s);
120865942Sgibbs					xpt_done(ccb);
120965942Sgibbs					return;
121065942Sgibbs				}
1211123579Sgibbs				sg->addr = aic_htole32(ahc->dma_bug_buf);
1212123579Sgibbs				sg->len = aic_htole32(1);
121365942Sgibbs				sg++;
121465942Sgibbs			}
121565942Sgibbs		}
121665942Sgibbs		sg--;
1217123579Sgibbs		sg->len |= aic_htole32(AHC_DMA_LAST_SEG);
121865942Sgibbs
121965942Sgibbs		/* Copy the first SG into the "current" data pointer area */
122065942Sgibbs		scb->hscb->dataptr = scb->sg_list->addr;
122165942Sgibbs		scb->hscb->datacnt = scb->sg_list->len;
122265942Sgibbs	} else {
1223123579Sgibbs		scb->hscb->sgptr = aic_htole32(SG_LIST_NULL);
122465942Sgibbs		scb->hscb->dataptr = 0;
122565942Sgibbs		scb->hscb->datacnt = 0;
122665942Sgibbs	}
122765942Sgibbs
122865942Sgibbs	scb->sg_count = nsegments;
122965942Sgibbs
123065942Sgibbs	ahc_lock(ahc, &s);
123165942Sgibbs
123265942Sgibbs	/*
123365942Sgibbs	 * Last time we need to check if this SCB needs to
123465942Sgibbs	 * be aborted.
123565942Sgibbs	 */
1236123579Sgibbs	if (aic_get_transaction_status(scb) != CAM_REQ_INPROG) {
123765942Sgibbs		if (nsegments != 0)
123895378Sgibbs			bus_dmamap_unload(ahc->buffer_dmat, scb->dmamap);
123965942Sgibbs		ahc_free_scb(ahc, scb);
124066647Sgibbs		ahc_unlock(ahc, &s);
124165942Sgibbs		xpt_done(ccb);
124265942Sgibbs		return;
124365942Sgibbs	}
124465942Sgibbs
124566717Sgibbs	tinfo = ahc_fetch_transinfo(ahc, SCSIID_CHANNEL(ahc, scb->hscb->scsiid),
124666717Sgibbs				    SCSIID_OUR_ID(scb->hscb->scsiid),
124768087Sgibbs				    SCSIID_TARGET(ahc, scb->hscb->scsiid),
124868087Sgibbs				    &tstate);
124966717Sgibbs
125066717Sgibbs	mask = SCB_GET_TARGET_MASK(ahc, scb);
125166717Sgibbs	scb->hscb->scsirate = tinfo->scsirate;
125276634Sgibbs	scb->hscb->scsioffset = tinfo->curr.offset;
125366717Sgibbs	if ((tstate->ultraenb & mask) != 0)
125466717Sgibbs		scb->hscb->control |= ULTRAENB;
125574972Sgibbs
125666717Sgibbs	if ((tstate->discenable & mask) != 0
125766717Sgibbs	 && (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) == 0)
125866717Sgibbs		scb->hscb->control |= DISCENB;
125966717Sgibbs
126066717Sgibbs	if ((ccb->ccb_h.flags & CAM_NEGOTIATE) != 0
126170204Sgibbs	 && (tinfo->goal.width != 0
1262102674Sgibbs	  || tinfo->goal.offset != 0
126370204Sgibbs	  || tinfo->goal.ppr_options != 0)) {
126466717Sgibbs		scb->flags |= SCB_NEGOTIATE;
126566717Sgibbs		scb->hscb->control |= MK_MESSAGE;
126674972Sgibbs	} else if ((tstate->auto_negotiate & mask) != 0) {
126774972Sgibbs		scb->flags |= SCB_AUTO_NEGOTIATE;
126874972Sgibbs		scb->hscb->control |= MK_MESSAGE;
126966717Sgibbs	}
127066717Sgibbs
127165942Sgibbs	LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links);
127265942Sgibbs
127365942Sgibbs	ccb->ccb_h.status |= CAM_SIM_QUEUED;
127465942Sgibbs
127565942Sgibbs	/*
127665942Sgibbs	 * We only allow one untagged transaction
127765942Sgibbs	 * per target in the initiator role unless
127865942Sgibbs	 * we are storing a full busy target *lun*
127965942Sgibbs	 * table in SCB space.
128065942Sgibbs	 */
128165942Sgibbs	if ((scb->hscb->control & (TARGET_SCB|TAG_ENB)) == 0
128271390Sgibbs	 && (ahc->flags & AHC_SCB_BTT) == 0) {
128365942Sgibbs		struct scb_tailq *untagged_q;
128472811Sgibbs		int target_offset;
128565942Sgibbs
128672811Sgibbs		target_offset = SCB_GET_TARGET_OFFSET(ahc, scb);
128772811Sgibbs		untagged_q = &(ahc->untagged_queues[target_offset]);
128865942Sgibbs		TAILQ_INSERT_TAIL(untagged_q, scb, links.tqe);
128966986Sgibbs		scb->flags |= SCB_UNTAGGEDQ;
129065942Sgibbs		if (TAILQ_FIRST(untagged_q) != scb) {
129165942Sgibbs			ahc_unlock(ahc, &s);
129265942Sgibbs			return;
129365942Sgibbs		}
129465942Sgibbs	}
129565942Sgibbs	scb->flags |= SCB_ACTIVE;
129665942Sgibbs
1297133911Sgibbs	/*
1298133911Sgibbs	 * Timers are disabled while recovery is in progress.
1299133911Sgibbs	 */
1300133911Sgibbs	aic_scb_timer_start(scb);
1301133911Sgibbs
130265942Sgibbs	if ((scb->flags & SCB_TARGET_IMMEDIATE) != 0) {
130374972Sgibbs		/* Define a mapping from our tag to the SCB. */
130474972Sgibbs		ahc->scb_data->scbindex[scb->hscb->tag] = scb;
130574094Sgibbs		ahc_pause(ahc);
130665942Sgibbs		if ((ahc->flags & AHC_PAGESCBS) == 0)
130765942Sgibbs			ahc_outb(ahc, SCBPTR, scb->hscb->tag);
1308102674Sgibbs		ahc_outb(ahc, TARG_IMMEDIATE_SCB, scb->hscb->tag);
130974094Sgibbs		ahc_unpause(ahc);
131065942Sgibbs	} else {
131165942Sgibbs		ahc_queue_scb(ahc, scb);
131265942Sgibbs	}
131365942Sgibbs
131465942Sgibbs	ahc_unlock(ahc, &s);
131565942Sgibbs}
131665942Sgibbs
131765942Sgibbsstatic void
131865942Sgibbsahc_poll(struct cam_sim *sim)
131965942Sgibbs{
1320102674Sgibbs	struct ahc_softc *ahc;
1321102674Sgibbs
1322102674Sgibbs	ahc = (struct ahc_softc *)cam_sim_softc(sim);
1323102674Sgibbs	ahc_intr(ahc);
132465942Sgibbs}
132565942Sgibbs
132665942Sgibbsstatic void
132765942Sgibbsahc_setup_data(struct ahc_softc *ahc, struct cam_sim *sim,
132865942Sgibbs	       struct ccb_scsiio *csio, struct scb *scb)
132965942Sgibbs{
133065942Sgibbs	struct hardware_scb *hscb;
133165942Sgibbs	struct ccb_hdr *ccb_h;
133265942Sgibbs
133365942Sgibbs	hscb = scb->hscb;
133465942Sgibbs	ccb_h = &csio->ccb_h;
133565942Sgibbs
133679874Sgibbs	csio->resid = 0;
133779874Sgibbs	csio->sense_resid = 0;
133865942Sgibbs	if (ccb_h->func_code == XPT_SCSI_IO) {
133965942Sgibbs		hscb->cdb_len = csio->cdb_len;
134065942Sgibbs		if ((ccb_h->flags & CAM_CDB_POINTER) != 0) {
134165942Sgibbs
134265942Sgibbs			if (hscb->cdb_len > sizeof(hscb->cdb32)
134365942Sgibbs			 || (ccb_h->flags & CAM_CDB_PHYS) != 0) {
134466647Sgibbs				u_long s;
134566647Sgibbs
1346123579Sgibbs				aic_set_transaction_status(scb,
134765942Sgibbs							   CAM_REQ_INVALID);
134866647Sgibbs				ahc_lock(ahc, &s);
134965942Sgibbs				ahc_free_scb(ahc, scb);
135066647Sgibbs				ahc_unlock(ahc, &s);
135166647Sgibbs				xpt_done((union ccb *)csio);
135265942Sgibbs				return;
135365942Sgibbs			}
135465942Sgibbs			if (hscb->cdb_len > 12) {
135565942Sgibbs				memcpy(hscb->cdb32,
135665942Sgibbs				       csio->cdb_io.cdb_ptr,
135765942Sgibbs				       hscb->cdb_len);
135868087Sgibbs				scb->flags |= SCB_CDB32_PTR;
135965942Sgibbs			} else {
136065942Sgibbs				memcpy(hscb->shared_data.cdb,
136165942Sgibbs				       csio->cdb_io.cdb_ptr,
136265942Sgibbs				       hscb->cdb_len);
136365942Sgibbs			}
136465942Sgibbs		} else {
136565942Sgibbs			if (hscb->cdb_len > 12) {
136665942Sgibbs				memcpy(hscb->cdb32, csio->cdb_io.cdb_bytes,
136765942Sgibbs				       hscb->cdb_len);
136868087Sgibbs				scb->flags |= SCB_CDB32_PTR;
136965942Sgibbs			} else {
137065942Sgibbs				memcpy(hscb->shared_data.cdb,
137165942Sgibbs				       csio->cdb_io.cdb_bytes,
137265942Sgibbs				       hscb->cdb_len);
137365942Sgibbs			}
137465942Sgibbs		}
137565942Sgibbs	}
137665942Sgibbs
137765942Sgibbs	/* Only use S/G if there is a transfer */
137865942Sgibbs	if ((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
137965942Sgibbs		if ((ccb_h->flags & CAM_SCATTER_VALID) == 0) {
138065942Sgibbs			/* We've been given a pointer to a single buffer */
138165942Sgibbs			if ((ccb_h->flags & CAM_DATA_PHYS) == 0) {
138265942Sgibbs				int s;
138365942Sgibbs				int error;
138465942Sgibbs
138565942Sgibbs				s = splsoftvm();
138665942Sgibbs				error = bus_dmamap_load(ahc->buffer_dmat,
138765942Sgibbs							scb->dmamap,
138865942Sgibbs							csio->data_ptr,
138965942Sgibbs							csio->dxfer_len,
139065942Sgibbs							ahc_execute_scb,
139165942Sgibbs							scb, /*flags*/0);
139265942Sgibbs				if (error == EINPROGRESS) {
139365942Sgibbs					/*
139465942Sgibbs					 * So as to maintain ordering,
139565942Sgibbs					 * freeze the controller queue
139665942Sgibbs					 * until our mapping is
139765942Sgibbs					 * returned.
139865942Sgibbs					 */
139965942Sgibbs					xpt_freeze_simq(sim,
140065942Sgibbs							/*count*/1);
140165942Sgibbs					scb->io_ctx->ccb_h.status |=
140265942Sgibbs					    CAM_RELEASE_SIMQ;
140365942Sgibbs				}
140465942Sgibbs				splx(s);
140565942Sgibbs			} else {
140665942Sgibbs				struct bus_dma_segment seg;
140765942Sgibbs
140865942Sgibbs				/* Pointer to physical buffer */
140965942Sgibbs				if (csio->dxfer_len > AHC_MAXTRANSFER_SIZE)
141065942Sgibbs					panic("ahc_setup_data - Transfer size "
141165942Sgibbs					      "larger than can device max");
141265942Sgibbs
1413112842Sjake				seg.ds_addr =
1414112842Sjake				    (bus_addr_t)(vm_offset_t)csio->data_ptr;
141565942Sgibbs				seg.ds_len = csio->dxfer_len;
141665942Sgibbs				ahc_execute_scb(scb, &seg, 1, 0);
141765942Sgibbs			}
141865942Sgibbs		} else {
141965942Sgibbs			struct bus_dma_segment *segs;
142065942Sgibbs
142165942Sgibbs			if ((ccb_h->flags & CAM_DATA_PHYS) != 0)
142265942Sgibbs				panic("ahc_setup_data - Physical segment "
142365942Sgibbs				      "pointers unsupported");
142465942Sgibbs
142565942Sgibbs			if ((ccb_h->flags & CAM_SG_LIST_PHYS) == 0)
142665942Sgibbs				panic("ahc_setup_data - Virtual segment "
142765942Sgibbs				      "addresses unsupported");
142865942Sgibbs
142965942Sgibbs			/* Just use the segments provided */
143065942Sgibbs			segs = (struct bus_dma_segment *)csio->data_ptr;
143165942Sgibbs			ahc_execute_scb(scb, segs, csio->sglist_cnt, 0);
143265942Sgibbs		}
143365942Sgibbs	} else {
143465942Sgibbs		ahc_execute_scb(scb, NULL, 0, 0);
143565942Sgibbs	}
143665942Sgibbs}
143765942Sgibbs
143865942Sgibbsstatic void
143965942Sgibbsahc_abort_ccb(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
144065942Sgibbs{
144165942Sgibbs	union ccb *abort_ccb;
144265942Sgibbs
144365942Sgibbs	abort_ccb = ccb->cab.abort_ccb;
144465942Sgibbs	switch (abort_ccb->ccb_h.func_code) {
144565942Sgibbs	case XPT_ACCEPT_TARGET_IO:
144665942Sgibbs	case XPT_IMMED_NOTIFY:
144765942Sgibbs	case XPT_CONT_TARGET_IO:
144865942Sgibbs	{
144974972Sgibbs		struct ahc_tmode_tstate *tstate;
145074972Sgibbs		struct ahc_tmode_lstate *lstate;
145165942Sgibbs		struct ccb_hdr_slist *list;
145265942Sgibbs		cam_status status;
145365942Sgibbs
145465942Sgibbs		status = ahc_find_tmode_devs(ahc, sim, abort_ccb, &tstate,
145565942Sgibbs					     &lstate, TRUE);
145665942Sgibbs
145765942Sgibbs		if (status != CAM_REQ_CMP) {
145865942Sgibbs			ccb->ccb_h.status = status;
145965942Sgibbs			break;
146065942Sgibbs		}
146165942Sgibbs
146265942Sgibbs		if (abort_ccb->ccb_h.func_code == XPT_ACCEPT_TARGET_IO)
146365942Sgibbs			list = &lstate->accept_tios;
146465942Sgibbs		else if (abort_ccb->ccb_h.func_code == XPT_IMMED_NOTIFY)
146565942Sgibbs			list = &lstate->immed_notifies;
146665942Sgibbs		else
146765942Sgibbs			list = NULL;
146865942Sgibbs
146965942Sgibbs		if (list != NULL) {
147065942Sgibbs			struct ccb_hdr *curelm;
147165942Sgibbs			int found;
147265942Sgibbs
147365942Sgibbs			curelm = SLIST_FIRST(list);
147465942Sgibbs			found = 0;
147565942Sgibbs			if (curelm == &abort_ccb->ccb_h) {
147665942Sgibbs				found = 1;
147765942Sgibbs				SLIST_REMOVE_HEAD(list, sim_links.sle);
147865942Sgibbs			} else {
147965942Sgibbs				while(curelm != NULL) {
148065942Sgibbs					struct ccb_hdr *nextelm;
148165942Sgibbs
148265942Sgibbs					nextelm =
148365942Sgibbs					    SLIST_NEXT(curelm, sim_links.sle);
148465942Sgibbs
148565942Sgibbs					if (nextelm == &abort_ccb->ccb_h) {
148665942Sgibbs						found = 1;
148765942Sgibbs						SLIST_NEXT(curelm,
148865942Sgibbs							   sim_links.sle) =
148965942Sgibbs						    SLIST_NEXT(nextelm,
149065942Sgibbs							       sim_links.sle);
149165942Sgibbs						break;
149265942Sgibbs					}
149365942Sgibbs					curelm = nextelm;
149465942Sgibbs				}
149565942Sgibbs			}
149665942Sgibbs
149765942Sgibbs			if (found) {
149865942Sgibbs				abort_ccb->ccb_h.status = CAM_REQ_ABORTED;
149965942Sgibbs				xpt_done(abort_ccb);
150065942Sgibbs				ccb->ccb_h.status = CAM_REQ_CMP;
150165942Sgibbs			} else {
150268087Sgibbs				xpt_print_path(abort_ccb->ccb_h.path);
150365942Sgibbs				printf("Not found\n");
150465942Sgibbs				ccb->ccb_h.status = CAM_PATH_INVALID;
150565942Sgibbs			}
150665942Sgibbs			break;
150765942Sgibbs		}
150865942Sgibbs		/* FALLTHROUGH */
150965942Sgibbs	}
151065942Sgibbs	case XPT_SCSI_IO:
151165942Sgibbs		/* XXX Fully implement the hard ones */
151265942Sgibbs		ccb->ccb_h.status = CAM_UA_ABORT;
151365942Sgibbs		break;
151465942Sgibbs	default:
151565942Sgibbs		ccb->ccb_h.status = CAM_REQ_INVALID;
151665942Sgibbs		break;
151765942Sgibbs	}
151865942Sgibbs	xpt_done(ccb);
151965942Sgibbs}
152065942Sgibbs
152165942Sgibbsvoid
152266269Sgibbsahc_send_async(struct ahc_softc *ahc, char channel, u_int target,
152376634Sgibbs		u_int lun, ac_code code, void *opt_arg)
152465942Sgibbs{
152565942Sgibbs	struct	ccb_trans_settings cts;
152665942Sgibbs	struct cam_path *path;
152765942Sgibbs	void *arg;
152865942Sgibbs	int error;
152965942Sgibbs
153065942Sgibbs	arg = NULL;
153166269Sgibbs	error = ahc_create_path(ahc, channel, target, lun, &path);
153265942Sgibbs
153365942Sgibbs	if (error != CAM_REQ_CMP)
153465942Sgibbs		return;
153565942Sgibbs
153665942Sgibbs	switch (code) {
153765942Sgibbs	case AC_TRANSFER_NEG:
153876634Sgibbs	{
153965942Sgibbs#ifdef AHC_NEW_TRAN_SETTINGS
154076634Sgibbs		struct	ccb_trans_settings_scsi *scsi;
154176634Sgibbs
154265942Sgibbs		cts.type = CTS_TYPE_CURRENT_SETTINGS;
154376634Sgibbs		scsi = &cts.proto_specific.scsi;
154465942Sgibbs#else
154565942Sgibbs		cts.flags = CCB_TRANS_CURRENT_SETTINGS;
154665942Sgibbs#endif
154765942Sgibbs		cts.ccb_h.path = path;
154866269Sgibbs		cts.ccb_h.target_id = target;
154966269Sgibbs		cts.ccb_h.target_lun = lun;
155066269Sgibbs		ahc_get_tran_settings(ahc, channel == 'A' ? ahc->our_id
155166269Sgibbs							  : ahc->our_id_b,
155266269Sgibbs				      channel, &cts);
155365942Sgibbs		arg = &cts;
155476634Sgibbs#ifdef AHC_NEW_TRAN_SETTINGS
155576634Sgibbs		scsi->valid &= ~CTS_SCSI_VALID_TQ;
155676634Sgibbs		scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
155776634Sgibbs#else
155876634Sgibbs		cts.valid &= ~CCB_TRANS_TQ_VALID;
155976634Sgibbs		cts.flags &= ~CCB_TRANS_TAG_ENB;
156076634Sgibbs#endif
156176634Sgibbs		if (opt_arg == NULL)
156276634Sgibbs			break;
156376634Sgibbs		if (*((ahc_queue_alg *)opt_arg) == AHC_QUEUE_TAGGED)
156476634Sgibbs#ifdef AHC_NEW_TRAN_SETTINGS
156576634Sgibbs			scsi->flags |= ~CTS_SCSI_FLAGS_TAG_ENB;
156676634Sgibbs		scsi->valid |= CTS_SCSI_VALID_TQ;
156776634Sgibbs#else
156876634Sgibbs			cts.flags |= CCB_TRANS_TAG_ENB;
156976634Sgibbs		cts.valid |= CCB_TRANS_TQ_VALID;
157076634Sgibbs#endif
157165942Sgibbs		break;
157276634Sgibbs	}
157365942Sgibbs	case AC_SENT_BDR:
157465942Sgibbs	case AC_BUS_RESET:
157565942Sgibbs		break;
157665942Sgibbs	default:
157765942Sgibbs		panic("ahc_send_async: Unexpected async event");
157865942Sgibbs	}
157965942Sgibbs	xpt_async(code, path, arg);
158068402Sgibbs	xpt_free_path(path);
158165942Sgibbs}
158265942Sgibbs
158365942Sgibbsvoid
158465942Sgibbsahc_platform_set_tags(struct ahc_softc *ahc,
158565942Sgibbs		      struct ahc_devinfo *devinfo, int enable)
158665942Sgibbs{
158765942Sgibbs}
158865942Sgibbs
158965942Sgibbsint
159065942Sgibbsahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg)
159165942Sgibbs{
159267888Sdwmalone	ahc->platform_data = malloc(sizeof(struct ahc_platform_data), M_DEVBUF,
159367888Sdwmalone	    M_NOWAIT | M_ZERO);
159465942Sgibbs	if (ahc->platform_data == NULL)
159565942Sgibbs		return (ENOMEM);
159665942Sgibbs	return (0);
159765942Sgibbs}
159865942Sgibbs
159965942Sgibbsvoid
160065942Sgibbsahc_platform_free(struct ahc_softc *ahc)
160165942Sgibbs{
160270204Sgibbs	struct ahc_platform_data *pdata;
160370204Sgibbs
160470204Sgibbs	pdata = ahc->platform_data;
160570204Sgibbs	if (pdata != NULL) {
160670204Sgibbs		if (pdata->regs != NULL)
160765942Sgibbs			bus_release_resource(ahc->dev_softc,
160870204Sgibbs					     pdata->regs_res_type,
160970204Sgibbs					     pdata->regs_res_id,
161070204Sgibbs					     pdata->regs);
161165942Sgibbs
161270204Sgibbs		if (pdata->irq != NULL)
161365942Sgibbs			bus_release_resource(ahc->dev_softc,
161470204Sgibbs					     pdata->irq_res_type,
161570204Sgibbs					     0, pdata->irq);
161665942Sgibbs
161770204Sgibbs		if (pdata->sim_b != NULL) {
161870204Sgibbs			xpt_async(AC_LOST_DEVICE, pdata->path_b, NULL);
161970204Sgibbs			xpt_free_path(pdata->path_b);
162070204Sgibbs			xpt_bus_deregister(cam_sim_path(pdata->sim_b));
162170204Sgibbs			cam_sim_free(pdata->sim_b, /*free_devq*/TRUE);
162270204Sgibbs		}
162370204Sgibbs		if (pdata->sim != NULL) {
162470204Sgibbs			xpt_async(AC_LOST_DEVICE, pdata->path, NULL);
162570204Sgibbs			xpt_free_path(pdata->path);
162670204Sgibbs			xpt_bus_deregister(cam_sim_path(pdata->sim));
162770204Sgibbs			cam_sim_free(pdata->sim, /*free_devq*/TRUE);
162870204Sgibbs		}
162970204Sgibbs		if (pdata->eh != NULL)
163070204Sgibbs			EVENTHANDLER_DEREGISTER(shutdown_final, pdata->eh);
163165942Sgibbs		free(ahc->platform_data, M_DEVBUF);
163265942Sgibbs	}
163365942Sgibbs}
163465942Sgibbs
163565942Sgibbsint
163665942Sgibbsahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc)
163765942Sgibbs{
163865942Sgibbs	/* We don't sort softcs under FreeBSD so report equal always */
163965942Sgibbs	return (0);
164065942Sgibbs}
164165942Sgibbs
164270204Sgibbsint
164370204Sgibbsahc_detach(device_t dev)
164470204Sgibbs{
164570204Sgibbs	struct ahc_softc *ahc;
1646102674Sgibbs	u_long l;
164770204Sgibbs	u_long s;
164870204Sgibbs
1649102674Sgibbs	ahc_list_lock(&l);
165070204Sgibbs	device_printf(dev, "detaching device\n");
165170204Sgibbs	ahc = device_get_softc(dev);
1652102674Sgibbs	ahc = ahc_find_softc(ahc);
1653102674Sgibbs	if (ahc == NULL) {
1654102674Sgibbs		device_printf(dev, "aic7xxx already detached\n");
1655102674Sgibbs		ahc_list_unlock(&l);
1656102674Sgibbs		return (ENOENT);
1657102674Sgibbs	}
1658123579Sgibbs	TAILQ_REMOVE(&ahc_tailq, ahc, links);
1659123579Sgibbs	ahc_list_unlock(&l);
166070204Sgibbs	ahc_lock(ahc, &s);
1661102674Sgibbs	ahc_intr_enable(ahc, FALSE);
166270204Sgibbs	bus_teardown_intr(dev, ahc->platform_data->irq, ahc->platform_data->ih);
166370204Sgibbs	ahc_unlock(ahc, &s);
166470204Sgibbs	ahc_free(ahc);
166570204Sgibbs	return (0);
166670204Sgibbs}
166770204Sgibbs
166865942Sgibbs#if UNUSED
166965942Sgibbsstatic void
167065942Sgibbsahc_dump_targcmd(struct target_cmd *cmd)
167165942Sgibbs{
167265942Sgibbs	uint8_t *byte;
167365942Sgibbs	uint8_t *last_byte;
167465942Sgibbs	int i;
167565942Sgibbs
167665942Sgibbs	byte = &cmd->initiator_channel;
167765942Sgibbs	/* Debugging info for received commands */
167865942Sgibbs	last_byte = &cmd[1].initiator_channel;
167965942Sgibbs
168065942Sgibbs	i = 0;
168165942Sgibbs	while (byte < last_byte) {
168265942Sgibbs		if (i == 0)
168365942Sgibbs			printf("\t");
168465942Sgibbs		printf("%#x", *byte++);
168565942Sgibbs		i++;
168665942Sgibbs		if (i == 8) {
168765942Sgibbs			printf("\n");
168865942Sgibbs			i = 0;
168965942Sgibbs		} else {
169065942Sgibbs			printf(", ");
169165942Sgibbs		}
169265942Sgibbs	}
169365942Sgibbs}
169465942Sgibbs#endif
169576634Sgibbs
169676634Sgibbsstatic int
169776634Sgibbsahc_modevent(module_t mod, int type, void *data)
169876634Sgibbs{
169976634Sgibbs	/* XXX Deal with busy status on unload. */
1700132199Sphk	/* XXX Deal with unknown events */
170176634Sgibbs	return 0;
170276634Sgibbs}
170376634Sgibbs
170476634Sgibbsstatic moduledata_t ahc_mod = {
170576634Sgibbs	"ahc",
170676634Sgibbs	ahc_modevent,
170776634Sgibbs	NULL
170876634Sgibbs};
170976634Sgibbs
171076634SgibbsDECLARE_MODULE(ahc, ahc_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
171176634SgibbsMODULE_DEPEND(ahc, cam, 1, 1, 1);
171276634SgibbsMODULE_VERSION(ahc, 1);
1713